From 15cb3984cafd893d4c00b75f9b92eb9cda6d52b4 Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Sat, 11 Jan 2025 08:00:24 +0530 Subject: [PATCH 1/2] Init --- .../saml-authenticator-form-finalform.tsx | 122 ++++++++++++++++++ .../saml-authenticator-form.tsx | 9 +- 2 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form-finalform.tsx diff --git a/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form-finalform.tsx b/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form-finalform.tsx new file mode 100644 index 00000000000..c0660581271 --- /dev/null +++ b/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form-finalform.tsx @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ConfigReducerStateInterface } from "@wso2is/admin.core.v1"; +import { AppState } from "@wso2is/admin.core.v1/store"; +import { FinalForm, FinalFormField, FormRenderProps } from "@wso2is/form/src"; +import { Code, FormInputLabel } from "@wso2is/react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { useSelector } from "react-redux"; +import { SERVICE_PROVIDER_ENTITY_ID_LENGTH } from "../../../../utils/saml-idp-utils"; +import { IdentifiableComponentInterface } from "@wso2is/core/models"; +import { AuthenticatorSettingsFormModes, CommonAuthenticatorFormInitialValuesInterface } from "../../../../models/authenticators"; +import { FederatedAuthenticatorWithMetaInterface } from "../../../../models/connection"; + +/** + * The i18n namespace entry key for this component's contents. + * Optionally you can pass this key to {@link useTranslation} + * to avoid concatenate strings. + */ +const I18N_TARGET_KEY: string = "authenticationProvider:forms.authenticatorSettings.saml"; + +/** + * SamlSettingsForm Properties interface. The data-testid is added in + * {@link SamlAuthenticatorSettingsForm.defaultProps}. + */ +interface SamlSettingsFormPropsInterface extends IdentifiableComponentInterface { + /** + * The intended mode of the authenticator form. + * If the mode is "EDIT", the form will be used in the edit view and will rely on metadata for readonly states, etc. + * If the mode is "CREATE", the form will be used in the add wizards and will all the fields will be editable. + */ + mode: AuthenticatorSettingsFormModes; + authenticator: FederatedAuthenticatorWithMetaInterface; + onSubmit: (values: CommonAuthenticatorFormInitialValuesInterface) => void; + readOnly?: boolean; + /** + * Specifies if the form is submitted. + */ + isSubmitting?: boolean; +} + +export default function SamlAuthenticatorSettingsForm(props: SamlSettingsFormPropsInterface) { + + const { + authenticator, + onSubmit, + readOnly, + isSubmitting, + [ "data-componentid" ]: componentId = "saml-authenticator-settings-form" + } = props; + + const handleSubmit = () => {}; + + const { t } = useTranslation(); + + const config: ConfigReducerStateInterface = useSelector((state: AppState) => state.config); + + return ( + { + console.log(values); + } } + initialValues={ { + SPEntityId: "" + } } + render={ ({ handleSubmit }: FormRenderProps) => ( +
+ + { t(`${ I18N_TARGET_KEY }.SPEntityId.label`) } + + ) } + hint={ ( + <> + This value will be used as the <saml2:Issuer> in + the SAML requests initiated from { config.ui.productName } to external + Identity Provider (IdP). You need to provide a unique value + as the service provider entityId. + + ) } + readOnly={ readOnly } + + /> + + + + + + + + + + + + ) } + >
+ ); +} diff --git a/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form.tsx b/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form.tsx index bae0e14873b..21a6e948d00 100644 --- a/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form.tsx +++ b/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form.tsx @@ -136,7 +136,7 @@ export const SamlAuthenticatorSettingsForm: FunctionComponent @@ -1081,13 +1081,6 @@ export const SamlAuthenticatorSettingsForm: FunctionComponent> = ( { width = 16, children }: PropsWithChildren<{ width?: SemanticWIDTHS }> ): ReactElement => { From 394f0633bb3b22c725e4f331fe45455da3c60c8f Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Fri, 17 Jan 2025 19:19:35 +0530 Subject: [PATCH 2/2] Move saml idp settings form impl. to final form --- .../saml-authenticator-form-finalform.tsx | 1060 ++++++++++++++++- .../saml-authenticator-form.tsx | 3 + .../factories/authenticator-form-factory.tsx | 34 +- 3 files changed, 1053 insertions(+), 44 deletions(-) diff --git a/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form-finalform.tsx b/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form-finalform.tsx index c0660581271..00c170f87ec 100644 --- a/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form-finalform.tsx +++ b/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form-finalform.tsx @@ -16,17 +16,50 @@ * under the License. */ +import Autocomplete, { AutocompleteRenderInputParams } from "@oxygen-ui/react/Autocomplete"; +import Button from "@oxygen-ui/react/Button"; +import TextField from "@oxygen-ui/react/TextField"; +import Typography from "@oxygen-ui/react/Typography"; import { ConfigReducerStateInterface } from "@wso2is/admin.core.v1"; import { AppState } from "@wso2is/admin.core.v1/store"; -import { FinalForm, FinalFormField, FormRenderProps } from "@wso2is/form/src"; -import { Code, FormInputLabel } from "@wso2is/react-components"; -import React from "react"; +import { identityProviderConfig } from "@wso2is/admin.extensions.v1/configs/identity-provider"; +import { IdentifiableComponentInterface } from "@wso2is/core/models"; +import { + CheckboxFieldAdapter, + DropdownChild, + FinalForm, + FinalFormField, + FormRenderProps, + FormSpy, + RadioGroupFieldAdapter, + SelectFieldAdapter, + TextFieldAdapter +} from "@wso2is/form/src"; +import { Code, FormInputLabel, FormSection, Hint } from "@wso2is/react-components"; +import React, { FunctionComponent, PropsWithChildren, ReactElement, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; -import { SERVICE_PROVIDER_ENTITY_ID_LENGTH } from "../../../../utils/saml-idp-utils"; -import { IdentifiableComponentInterface } from "@wso2is/core/models"; -import { AuthenticatorSettingsFormModes, CommonAuthenticatorFormInitialValuesInterface } from "../../../../models/authenticators"; +import { Divider, Grid, SemanticWIDTHS } from "semantic-ui-react"; +import { + AuthenticatorSettingsFormModes, + CommonAuthenticatorFormInitialValuesInterface +} from "../../../../models/authenticators"; import { FederatedAuthenticatorWithMetaInterface } from "../../../../models/connection"; +import { + DEFAULT_NAME_ID_FORMAT, + DEFAULT_PROTOCOL_BINDING, + IDENTITY_PROVIDER_AUTHENTICATION_REQUEST_PROVIDER_NAME_LENGTH, + IDENTITY_PROVIDER_AUTHORIZED_REDIRECT_URL_LENGTH, + IDENTITY_PROVIDER_ENTITY_ID_LENGTH, + LOGOUT_URL_LENGTH, + SERVICE_PROVIDER_ENTITY_ID_LENGTH, + SSO_URL_LENGTH, + fastSearch, + getAvailableNameIDFormats, + getAvailableProtocolBindingTypes, + getDigestAlgorithmOptionsMapped, + getSignatureAlgorithmOptionsMapped +} from "../../../../utils/saml-idp-utils"; /** * The i18n namespace entry key for this component's contents. @@ -55,68 +88,1021 @@ interface SamlSettingsFormPropsInterface extends IdentifiableComponentInterface isSubmitting?: boolean; } -export default function SamlAuthenticatorSettingsForm(props: SamlSettingsFormPropsInterface) { +export interface SamlPropertiesInterface { + AuthRedirectUrl?: string; + DigestAlgorithm?: string; + IdPEntityId?: string; + LogoutReqUrl?: string; + NameIDType?: string; + RequestMethod?: string; + SPEntityId?: string; + SSOUrl?: string; + SignatureAlgorithm?: string; + commonAuthQueryParams?: string; + customAuthnContextClassRef?: string; + ISAuthnReqSigned?: boolean; + IncludeProtocolBinding?: boolean; + IsAuthnRespSigned?: boolean; + IsLogoutEnabled?: boolean; + IsLogoutReqSigned?: boolean; + IsSLORequestAccepted?: boolean; + IsUserIdInClaims?: boolean; + ArtifactResolveUrl?: string; + ISArtifactBindingEnabled?: boolean; + /** + * https://github.com/wso2/product-is/issues/17004 + */ + ISArtifactResolveReqSigned?: boolean; + ISArtifactResponseSigned?: boolean; + isAssertionSigned?: boolean; + attributeConsumingServiceIndex?: string; + AuthnContextComparisonLevel?: string; + IsAssertionEncrypted?: boolean; + IncludeCert?: boolean; + IncludeNameIDPolicy?: boolean; + AuthnContextClassRef?: string; + AuthnReqProviderName?: string; +} +export default function SamlAuthenticatorSettingsFinalForm(props: SamlSettingsFormPropsInterface) { const { authenticator, onSubmit, readOnly, isSubmitting, - [ "data-componentid" ]: componentId = "saml-authenticator-settings-form" + ["data-componentid"]: componentId = "saml-authenticator-settings-form" } = props; - const handleSubmit = () => {}; - const { t } = useTranslation(); const config: ConfigReducerStateInterface = useSelector((state: AppState) => state.config); + const authorizedRedirectURL: string = config?.deployment?.customServerHost + "/commonauth"; + + const initialFormValues: SamlPropertiesInterface = useMemo(() => { + const [ findPropVal, findMeta ] = fastSearch(authenticator); + + return { + ArtifactResolveUrl: findPropVal({ defaultValue: "", key: "ArtifactResolveUrl" }), + AttributeConsumingServiceIndex: findPropVal({ + defaultValue: "", + key: "AttributeConsumingServiceIndex" + }), + AuthRedirectUrl: findPropVal({ defaultValue: authorizedRedirectURL, key: "AuthRedirectUrl" }), + AuthnContextClassRef: findPropVal({ defaultValue: "", key: "AuthnContextClassRef" }), + AuthnContextComparisonLevel: findPropVal({ defaultValue: "", key: "AuthnContextComparisonLevel" }), + AuthnReqProviderName: findPropVal({ defaultValue: "", key: "AuthnReqProviderName" }), + CustomAuthnContextClassRef: findPropVal({ defaultValue: "", key: "CustomAuthnContextClassRef" }), + DigestAlgorithm: findPropVal({ defaultValue: "SHA256", key: "DigestAlgorithm" }), + ForceAuthentication: findPropVal({ defaultValue: "string", key: "ForceAuthentication" }), + ISArtifactBindingEnabled: findPropVal({ defaultValue: false, key: "ISArtifactBindingEnabled" }), + /** + * https://github.com/wso2/product-is/issues/17004 + */ + ISArtifactResolveReqSigned: findPropVal({ + defaultValue: false, + key: "ISArtifactResolveReqSigned" + }), + ISArtifactResponseSigned: findPropVal({ defaultValue: false, key: "ISArtifactResponseSigned" }), + ISAuthnReqSigned: findPropVal({ defaultValue: false, key: "ISAuthnReqSigned" }), + IdPEntityId: findPropVal({ defaultValue: "", key: "IdPEntityId" }), + IncludeAuthnContext: findPropVal({ defaultValue: "string", key: "IncludeAuthnContext" }), + IncludeCert: findPropVal({ defaultValue: false, key: "IncludeCert" }), + IncludeNameIDPolicy: findPropVal({ defaultValue: false, key: "IncludeNameIDPolicy" }), + IncludeProtocolBinding: findPropVal({ defaultValue: false, key: "IncludeProtocolBinding" }), + /** + * `IsAuthnRespSigned` is by default set to true when creating the SAML IdP so, + * always the value will be true. Keeping this here to indicate for the user and + * to enable this if requirements gets changed. + */ + IsAssertionEncrypted: findPropVal({ defaultValue: false, key: "IsAssertionEncrypted" }), + IsAuthnRespSigned: findPropVal({ defaultValue: false, key: "IsAuthnRespSigned" }), + IsLogoutEnabled: findPropVal({ defaultValue: false, key: "IsLogoutEnabled" }), + IsLogoutReqSigned: findPropVal({ defaultValue: false, key: "IsLogoutReqSigned" }), + IsSLORequestAccepted: findPropVal({ defaultValue: false, key: "IsSLORequestAccepted" }), + IsUserIdInClaims: findPropVal({ defaultValue: false, key: "IsUserIdInClaims" }), + LogoutReqUrl: findPropVal({ defaultValue: "", key: "LogoutReqUrl" }), + NameIDType: findPropVal({ + defaultValue: findMeta({ key: "NameIDType" })?.defaultValue ?? DEFAULT_NAME_ID_FORMAT, + key: "NameIDType" + }), + RequestMethod: findPropVal({ + defaultValue: findMeta({ key: "RequestMethod" })?.defaultValue ?? DEFAULT_PROTOCOL_BINDING, + key: "RequestMethod" + }), + ResponseAuthnContextClassRef: findPropVal({ + defaultValue: "string", + key: "ResponseAuthnContextClassRef" + }), + SPEntityId: findPropVal({ defaultValue: "", key: "SPEntityId" }), + SSOUrl: findPropVal({ defaultValue: "", key: "SSOUrl" }), + SignatureAlgorithm: findPropVal({ defaultValue: "RSA with SHA256", key: "SignatureAlgorithm" }), + commonAuthQueryParams: findPropVal({ defaultValue: "", key: "commonAuthQueryParams" }), + /** + * https://github.com/wso2/product-is/issues/17004 + */ + isAssertionSigned: findPropVal({ defaultValue: false, key: "isAssertionSigned" }) + } as SamlPropertiesInterface; + }, []); + + const disabledFeatures: string[] = useSelector( + (state: AppState) => state.config.ui.features?.identityProviders?.disabledFeatures + ); + + const getAlgorithmsDropdownFieldValidators = (): ((value: string) => string | undefined) => { + // if (isLogoutReqSigned || isAuthnReqSigned) { + // return required; + // } + + return (/* No validations */) => void 0; + }; + + const getIncludeAuthenticationContextOptions = (): { + label: string; + value: string; + }[] => { + return [ + { label: "Yes", value: "yes" }, + { label: "No", value: "no" }, + { label: "As request", value: "as_request" } + ]; + }; + + const getForceAuthenticationOptions = (): { + label: string; + value: string; + }[] => { + return [ + { label: "Yes", value: "yes" }, + { label: "No", value: "no" }, + { label: "As request", value: "no-authn" } + ]; + }; + + const getResponseAuthnContextClassRefOptions = (): { + label: string; + value: string; + }[] => { + return [ + { label: "Default", value: "default" }, + { label: "As response", value: "as_response" } + ]; + }; + + const getAvailableAuthContextComparisonLevelOptions = (): DropdownChild[] => { + return [ + { key: 1, text: "Exact", value: "Exact" }, + { key: 2, text: "Minimum", value: "Minimum" }, + { key: 3, text: "Maximum", value: "Maximum" }, + { key: 4, text: "Better", value: "Better" } + ]; + }; + + const authenticationContextClassOptions: DropdownChild[] = [ + { key: 0, text: "Internet Protocol", value: "Internet Protocol" }, + { key: 1, text: "Internet Protocol Password", value: "Internet Protocol Password" }, + { key: 2, text: "Kerberos", value: "Kerberos" }, + { key: 3, text: "Mobile One Factor Unregistered", value: "Mobile One Factor Unregistered" }, + { key: 4, text: "Mobile Two Factor Unregistered", value: "Mobile Two Factor Unregistered" }, + { key: 5, text: "Mobile One Factor Contract", value: "Mobile One Factor Contract" }, + { key: 6, text: "Mobile Two Factor Contract", value: "Mobile Two Factor Contract" }, + { key: 7, text: "Password", value: "Password" }, + { key: 8, text: "Password Protected Transport", value: "Password Protected Transport (selected option)" }, + { key: 9, text: "Previous Session", value: "Previous Session" }, + { key: 10, text: "Public Key - X.509", value: "Public Key - X.509" }, + { key: 11, text: "Public Key - PGP", value: "Public Key - PGP" }, + { key: 12, text: "Public Key - SPKI", value: "Public Key - SPKI" }, + { key: 13, text: "Public Key - XML Digital Signature", value: "Public Key - XML Digital Signature" }, + { key: 14, text: "Smartcard", value: "Smartcard" }, + { key: 15, text: "Smartcard PKI", value: "Smartcard PKI" }, + { key: 16, text: "Software PKI", value: "Software PKI" }, + { key: 17, text: "Telephony", value: "Telephony" }, + { key: 18, text: "Telephony (Nomadic)", value: "Telephony (Nomadic)" }, + { key: 19, text: "Telephony (Personalized)", value: "Telephony (Personalized)" }, + { key: 20, text: "Telephony (Authenticated)", value: "Telephony (Authenticated)" }, + { key: 21, text: "Secure Remote Password", value: "Secure Remote Password" }, + { + key: 22, + text: "SSL/TLS Certificate-Based Client Authentication", + value: "SSL/TLS Certificate-Based Client Authentication" + }, + { key: 23, text: "Time Sync Token", value: "Time Sync Token" }, + { key: 24, text: "Unspecified", value: "Unspecified" }, + { key: 25, text: "Custom Authentication Context Class", value: "Custom Authentication Context Class" } + ]; + return ( { - console.log(values); - } } - initialValues={ { - SPEntityId: "" + onSubmit(values); } } + initialValues={ initialFormValues } render={ ({ handleSubmit }: FormRenderProps) => (
+ + + { t(`${I18N_TARGET_KEY}.SPEntityId.label`) } + ) + } + helperText={ + ( + This value will be used as the <saml2:Issuer> in the SAML requests + initiated from { config.ui.productName } to external Identity Provider (IdP). You need to + provide a unique value as the service provider entityId. + ) + } + readOnly={ readOnly } + /> + + + + + { t(`${I18N_TARGET_KEY}.SSOUrl.label`) } + + ) } + maxLength={ SSO_URL_LENGTH.max } + minLength={ SSO_URL_LENGTH.min } + component={ TextFieldAdapter } + helperText={ + ( + { t(`${I18N_TARGET_KEY}.SSOUrl.hint`, { + productName: config.ui.productName + }) } + ) + } + readOnly={ readOnly } + /> + + + + + { t(`${I18N_TARGET_KEY}.AuthRedirectUrl.label`) } + ) + } + maxLength={ IDENTITY_PROVIDER_AUTHORIZED_REDIRECT_URL_LENGTH.max } + minLength={ IDENTITY_PROVIDER_AUTHORIZED_REDIRECT_URL_LENGTH.min } + helperText={ + ( + { t(`${I18N_TARGET_KEY}.AuthRedirectUrl.hint`, { + productName: config.ui.productName + }) } + ) + } + component={ TextFieldAdapter } + readOnly={ readOnly } + /> + - { t(`${ I18N_TARGET_KEY }.SPEntityId.label`) } - - ) } - hint={ ( - <> - This value will be used as the <saml2:Issuer> in - the SAML requests initiated from { config.ui.productName } to external - Identity Provider (IdP). You need to provide a unique value - as the service provider entityId. - - ) } + placeholder={ t(`${I18N_TARGET_KEY}.IdPEntityId.placeholder`) } + ariaLabel={ t(`${I18N_TARGET_KEY}.IdPEntityId.ariaLabel`) } + data-testid={ `${componentId}-IdPEntityId-field` } + label={ + ( + { t(`${I18N_TARGET_KEY}.IdPEntityId.label`) } + ) + } + maxLength={ IDENTITY_PROVIDER_ENTITY_ID_LENGTH.max } + minLength={ IDENTITY_PROVIDER_ENTITY_ID_LENGTH.min } + component={ TextFieldAdapter } + helperText={ + ( + This is the <saml2:Issuer> value specified in the SAML responses + issued by the external IdP. Also, this needs to be a unique value to identify the + external IdP within your organization. + ) + } readOnly={ readOnly } + /> + + { t(`${I18N_TARGET_KEY}.NameIDType.label`) } + ) + } + type="dropdown" + helperText={ + ( + { t(`${I18N_TARGET_KEY}.NameIDType.hint`, { + productName: config.ui.productName + }) } + ) + } + readOnly={ readOnly } /> - + + { t(`${I18N_TARGET_KEY}.RequestMethod.label`) } + ) + } + helperText={ + ( + { t(`${I18N_TARGET_KEY}.RequestMethod.hint`) } + ) + } + component={ SelectFieldAdapter } + readOnly={ readOnly } + /> + + + + + + { t(`${I18N_TARGET_KEY}.IsSLORequestAccepted.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.IsSLORequestAccepted.hint`, { + productName: config.ui.productName + }) } + ) + } + component={ CheckboxFieldAdapter } + type="checkbox" + readOnly={ readOnly } + /> + + + + { t(`${I18N_TARGET_KEY}.IsLogoutEnabled.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.IsLogoutEnabled.hint`) } + ) + } + readOnly={ readOnly } + /> + + + + { t(`${I18N_TARGET_KEY}.LogoutReqUrl.label`) } + ) + } + maxLength={ LOGOUT_URL_LENGTH.max } + minLength={ LOGOUT_URL_LENGTH.min } + helperText={ + ( + { t(`${I18N_TARGET_KEY}.LogoutReqUrl.hint`) } + ) + } + readOnly={ readOnly } + /> + + + + + + + + + { t(`${I18N_TARGET_KEY}.IsAuthnRespSigned.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.IsAuthnRespSigned.hint`) } + ) + } + readOnly={ readOnly } + /> + + + + { t(`${I18N_TARGET_KEY}.IsLogoutReqSigned.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.IsLogoutReqSigned.hint`, { + productName: config.ui.productName + }) } + ) + } + // listen={ (checked: any) => setIsLogoutReqSigned(Boolean(checked)) } + readOnly={ readOnly } + /> + + + + { t(`${I18N_TARGET_KEY}.ISAuthnReqSigned.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.ISAuthnReqSigned.hint`, { + productName: config.ui.productName + }) } + ) + } + // listen={ (value: any) => setIsAuthnReqSigned(Boolean(value)) } + readOnly={ readOnly } + /> + + + + { ({ values }: { values: SamlPropertiesInterface }) => { + const isSignatureAlgorithmFieldEditable: boolean = + values.IsLogoutReqSigned || values.ISAuthnReqSigned; + + return ( + <> + + + { t(`${I18N_TARGET_KEY}.SignatureAlgorithm.label`) } + ) + } + validate={ getAlgorithmsDropdownFieldValidators() } + readOnly={ readOnly } + /> + + + + + { t(`${I18N_TARGET_KEY}.DigestAlgorithm.label`) } + ) + } + validate={ getAlgorithmsDropdownFieldValidators() } + readOnly={ readOnly } + /> + + + ); + } } + + + - + + + + + { t(`${I18N_TARGET_KEY}.IncludeProtocolBinding.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.IncludeProtocolBinding.hint`) } + ) + } + readOnly={ readOnly } + /> + + + + { t(`${I18N_TARGET_KEY}.IsUserIdInClaims.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.IsUserIdInClaims.hint`) } + ) + } + // listen={ (value: any) => setIsUserIdInClaims(Boolean(value)) } + readOnly={ readOnly } + /> + - + { identityProviderConfig?.extendedSamlConfig?.enableAssertionSigningEnabled && ( + + + { t(`${I18N_TARGET_KEY}.isAssertionSigned.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.isAssertionSigned.hint`) } + ) + } + readOnly={ readOnly } + /> + + ) } + { identityProviderConfig?.extendedSamlConfig?.includePublicCertEnabled && ( + + + { t(`${I18N_TARGET_KEY}.includeCert.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.includeCert.hint`) } + ) + } + // listen={ (value: any) => setIncludeCert(Boolean(value)) } + readOnly={ readOnly } + /> + + ) } + { identityProviderConfig?.extendedSamlConfig?.includeNameIDPolicyEnabled && ( + + + { t(`${I18N_TARGET_KEY}.includeNameIDPolicy.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.includeNameIDPolicy.hint`) } + ) + } + // listen={ (value: any) => setIncludeNameIDPolicy(Boolean(value)) } + readOnly={ readOnly } + /> + + ) } + { identityProviderConfig?.extendedSamlConfig?.isAssertionEncryptionEnabled && ( + + + { t(`${I18N_TARGET_KEY}.isEnableAssertionEncryption.label`) } + ) + } + hint={ + ( + { t(`${I18N_TARGET_KEY}.isEnableAssertionEncryption.hint`) } + ) + } + // listen={ (value: any) => setIsEnableAssetionEncryption(Boolean(value)) } + readOnly={ readOnly } + /> + + ) } + { identityProviderConfig.extendedSamlConfig.includeAuthenticationContextEnabled && ( + + { /* IncludeAuthnContext */ } +

Include authentication context

+ +
+ ) } - + { identityProviderConfig.extendedSamlConfig.forceAuthenticationEnabled && ( + + { /* ForceAuthentication */ } +

Force authentication

+ +
+ ) } - + { identityProviderConfig.extendedSamlConfig.responseAuthenticationContextClassEnabled && ( + +

Response Authentication Context Class

+ { /* ResponseAuthnContextClassRef */ } + +
+ ) } + + { identityProviderConfig.extendedSamlConfig.authContextComparisonLevelEnabled && ( + + + { t(`${I18N_TARGET_KEY}.authContextComparisonLevel.label`) } + ) + } + helperText={ + ( + { t(`${I18N_TARGET_KEY}.authContextComparisonLevel.hint`) } + ) + } + readOnly={ readOnly } + /> + + ) } + + { identityProviderConfig.extendedSamlConfig.attributeConsumingServiceIndexEnabled && ( + + + { t(`${I18N_TARGET_KEY}.attributeConsumingServiceIndex.label`) } + ) + } + maxLength={ LOGOUT_URL_LENGTH.max } + minLength={ LOGOUT_URL_LENGTH.min } + helperText={ + ( + { t(`${I18N_TARGET_KEY}.attributeConsumingServiceIndex.hint`) } + ) + } + readOnly={ readOnly } + /> + + ) } + + { !disabledFeatures?.includes("identityProviders.saml.authenticationContextClass") && ( + + + { t(`${I18N_TARGET_KEY}.authenticationContextClass.label`) } + + role?.text as string } + renderInput={ (params: AutocompleteRenderInputParams) => { + params.inputProps.className = "forms-wrapped-autocomplete-render-input"; + + return ( + + ); + } } + /> + + ) } + + { !disabledFeatures?.includes( + "identityProviders.saml.customAuthenticationContextClass" + ) && ( + + + { t(`${I18N_TARGET_KEY}.customAuthenticationContextClass.label`) } + ) + } + component={ TextFieldAdapter } + name="CustomAuthnContextClassRef" + maxLength={ 100 } + minLength={ 0 } + inputType="default" + placeholder={ t( + `${I18N_TARGET_KEY}.customAuthenticationContextClass.placeholder` + ) } + ariaLabel={ t(`${I18N_TARGET_KEY}.customAuthenticationContextClass.ariaLabel`) } + data-testid={ `${componentId}-customAuthenticationContextClass-field` } + /> + + ) } + + { /* */ } + + + + { t(`${I18N_TARGET_KEY}.authnReqProviderName.label`) } + ) + } + maxLength={ IDENTITY_PROVIDER_AUTHENTICATION_REQUEST_PROVIDER_NAME_LENGTH.max } + minLength={ IDENTITY_PROVIDER_AUTHENTICATION_REQUEST_PROVIDER_NAME_LENGTH.min } + helperText={ + ( + { t(`${I18N_TARGET_KEY}.authnReqProviderName.hint`) } + ) + } + readOnly={ readOnly } + /> + +
+
+ + { identityProviderConfig.extendedSamlConfig.isArtifactBindingEnabled && ( + + + + + { t(`${I18N_TARGET_KEY}.isArtifactBindingEnabled.label`) } + ) + } + readOnly={ readOnly } + /> + + + + { ({ values }: { values: SamlPropertiesInterface }) => { + return ( + <> + + + { t( + I18N_TARGET_KEY + + ".artifactResolveEndpointUrl.label" + ) } + ) + } + maxLength={ LOGOUT_URL_LENGTH.max } + minLength={ LOGOUT_URL_LENGTH.min } + readOnly={ readOnly } + disabled={ !values.ISArtifactBindingEnabled } + /> + + + + + { t( + I18N_TARGET_KEY + + ".isArtifactResolveReqSigned.label" + ) } + ) + } + readOnly={ readOnly } + disabled={ !values.ISArtifactBindingEnabled } + /> + + + + { t( + I18N_TARGET_KEY + + ".isArtifactResponseSigned.label" + ) } + ) + } + readOnly={ readOnly } + disabled={ !values.ISArtifactBindingEnabled } + /> + + + ); + } } + + + + ) } + + ) } >
); } + +const SectionRow: FunctionComponent> = ({ + width = 16, + children +}: PropsWithChildren<{ width?: SemanticWIDTHS }>): ReactElement => { + return ( + + { children } + + ); +}; diff --git a/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form.tsx b/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form.tsx index 21a6e948d00..6bad0109341 100644 --- a/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form.tsx +++ b/features/admin.connections.v1/components/edit/forms/authenticators/saml-authenticator-form.tsx @@ -341,6 +341,9 @@ export const SamlAuthenticatorSettingsForm: FunctionComponent { + + debugger; + const manualOverride: { [key: string]: boolean | string | string[] } = { "AuthnContextClassRef": selectedAuthnContextClasses?.map( (authnContextClass: DropdownChild) => authnContextClass.value diff --git a/features/admin.connections.v1/components/edit/forms/factories/authenticator-form-factory.tsx b/features/admin.connections.v1/components/edit/forms/factories/authenticator-form-factory.tsx index 11741d4ce3b..08b6f4795ba 100644 --- a/features/admin.connections.v1/components/edit/forms/factories/authenticator-form-factory.tsx +++ b/features/admin.connections.v1/components/edit/forms/factories/authenticator-form-factory.tsx @@ -19,6 +19,7 @@ import { identityProviderConfig } from "@wso2is/admin.extensions.v1/configs/identity-provider"; import { TestableComponentInterface } from "@wso2is/core/models"; import React, { FunctionComponent, ReactElement } from "react"; +import { Grid } from "semantic-ui-react"; import { CommonAuthenticatorConstants } from "../../../../constants/common-authenticator-constants"; import { FederatedAuthenticatorConstants } from "../../../../constants/federated-authenticator-constants"; import { LocalAuthenticatorConstants } from "../../../../constants/local-authenticator-constants"; @@ -42,6 +43,7 @@ import { SMSOTPAuthenticatorForm } from "../authenticators"; import { SamlAuthenticatorSettingsForm } from "../authenticators/saml-authenticator-form"; +import SamlAuthenticatorSettingsFinalForm from "../authenticators/saml-authenticator-form-finalform"; import { SIWEAuthenticatorForm } from "../authenticators/swe-authenticator-form"; /** @@ -247,13 +249,31 @@ export const AuthenticatorFormFactory: FunctionComponent + + + + + + + + + + + + + ); case FederatedAuthenticatorConstants.AUTHENTICATOR_IDS.MICROSOFT_AUTHENTICATOR_ID: if (templateId === CommonAuthenticatorConstants.CONNECTION_TEMPLATE_IDS.MICROSOFT){