diff --git a/README.md b/README.md index 99d5ab5d3..ec71c5eba 100644 --- a/README.md +++ b/README.md @@ -963,6 +963,16 @@ descope_client.mgmt.sso.configure_saml_settings_by_metadata( domains=["tenant-users.com"] # Users authentication with these domains will be logged in to this tenant ) +# Descope signs the SAML AuthnRequest it sends to the IdP. A few IdPs reject a signed request because +# their trusted provider entry holds no signing certificate for Descope - pass disable_sign_request +# (available on both settings classes above) to send the request unsigned for that configuration only. +settings = SSOSAMLSettings( + idp_url="https://dummy.com", + idp_entity_id="my-idp-entity-id", + idp_cert="my-idp-certificate", + disable_sign_request=True, +) + # You can Configure SSO OIDC settings for a tenant manually. settings = SSOOIDCSettings( name="myProvider", diff --git a/descope/management/_sso_settings_base.py b/descope/management/_sso_settings_base.py index 43b40a9f3..e6966a9e1 100644 --- a/descope/management/_sso_settings_base.py +++ b/descope/management/_sso_settings_base.py @@ -270,6 +270,9 @@ def _compose_configure_saml_settings_body( "fgaMappings": SSOSettingsBase._fga_mappings_to_dict(settings.fga_mappings), "configFGATenantIDResourcePrefix": settings.config_fga_tenant_id_resource_prefix, "configFGATenantIDResourceSuffix": settings.config_fga_tenant_id_resource_suffix, + # always sent: the server takes the settings object as a full replacement, so omitting the + # flag on an update would silently turn request signing back on + "disableSignRequest": settings.disable_sign_request, }, "redirectUrl": redirect_url, "domains": domains, @@ -300,6 +303,9 @@ def _compose_configure_saml_settings_by_metadata_body( "fgaMappings": SSOSettingsBase._fga_mappings_to_dict(settings.fga_mappings), "configFGATenantIDResourcePrefix": settings.config_fga_tenant_id_resource_prefix, "configFGATenantIDResourceSuffix": settings.config_fga_tenant_id_resource_suffix, + # always sent: the server takes the settings object as a full replacement, so omitting the + # flag on an update would silently turn request signing back on + "disableSignRequest": settings.disable_sign_request, }, "redirectUrl": redirect_url, "domains": domains, diff --git a/descope/management/sso_settings.py b/descope/management/sso_settings.py index 4afbda289..ed2e0c677 100644 --- a/descope/management/sso_settings.py +++ b/descope/management/sso_settings.py @@ -231,6 +231,10 @@ def __init__( # NOTICE - the following fields should be overridden only in case of SSO migration, otherwise, do not modify these fields sp_acs_url: Optional[str] = None, sp_entity_id: Optional[str] = None, + # Leave the SAML AuthnRequest Descope sends to the IdP unsigned. Set it only for IdPs that reject a + # signed request because their trusted provider entry holds no signing certificate for Descope. + # Appended last to preserve positional compatibility for existing callers. + disable_sign_request: bool = False, ): self.idp_url = idp_url self.idp_entity_id = idp_entity_id @@ -245,6 +249,7 @@ def __init__( self.fga_mappings = fga_mappings self.config_fga_tenant_id_resource_prefix = config_fga_tenant_id_resource_prefix self.config_fga_tenant_id_resource_suffix = config_fga_tenant_id_resource_suffix + self.disable_sign_request = disable_sign_request class SSOSAMLSettingsByMetadata: @@ -268,6 +273,9 @@ def __init__( # IdP entity ID - set so IdP-initiated login can resolve the tenant by the SAML response issuer. # Appended last to preserve positional compatibility for existing callers. idp_entity_id: Optional[str] = None, + # Leave the SAML AuthnRequest Descope sends to the IdP unsigned. Set it only for IdPs that reject a + # signed request because their trusted provider entry holds no signing certificate for Descope. + disable_sign_request: bool = False, ): self.idp_metadata_url = idp_metadata_url self.idp_entity_id = idp_entity_id @@ -280,6 +288,7 @@ def __init__( self.fga_mappings = fga_mappings self.config_fga_tenant_id_resource_prefix = config_fga_tenant_id_resource_prefix self.config_fga_tenant_id_resource_suffix = config_fga_tenant_id_resource_suffix + self.disable_sign_request = disable_sign_request class SSOSettings(SSOSettingsBase, HTTPBase): diff --git a/tests/management/test_sso_settings.py b/tests/management/test_sso_settings.py index 6882b4871..3af727cee 100644 --- a/tests/management/test_sso_settings.py +++ b/tests/management/test_sso_settings.py @@ -286,6 +286,7 @@ async def test_configure_saml_settings(self, client_factory): "fgaMappings": None, "configFGATenantIDResourcePrefix": None, "configFGATenantIDResourceSuffix": None, + "disableSignRequest": False, }, "redirectUrl": "https://redirect.com", "domains": ["domain.com"], @@ -642,6 +643,7 @@ async def test_configure_saml_settings_by_metadata(self, client_factory): "fgaMappings": None, "configFGATenantIDResourcePrefix": None, "configFGATenantIDResourceSuffix": None, + "disableSignRequest": False, }, "redirectUrl": "https://redirect.com", "domains": ["domain.com"], @@ -711,6 +713,7 @@ async def test_configure_saml_settings_with_additional_certs(self, client_factor "fgaMappings": None, "configFGATenantIDResourcePrefix": None, "configFGATenantIDResourceSuffix": None, + "disableSignRequest": False, }, "redirectUrl": "https://redirect.com", "domains": ["domain.com"], @@ -831,6 +834,7 @@ async def test_configure_saml_settings_with_fga_mappings(self, client_factory): }, "configFGATenantIDResourcePrefix": "tenant:", "configFGATenantIDResourceSuffix": "", + "disableSignRequest": False, }, "redirectUrl": "https://redirect.com", "domains": ["domain.com"], @@ -898,6 +902,7 @@ async def test_configure_saml_settings_by_metadata_with_fga_mappings(self, clien }, "configFGATenantIDResourcePrefix": "tenant:", "configFGATenantIDResourceSuffix": "-suffix", + "disableSignRequest": False, }, "redirectUrl": None, "domains": None,