diff --git a/descope/management/tenant.py b/descope/management/tenant.py index 92f797573..504a61907 100644 --- a/descope/management/tenant.py +++ b/descope/management/tenant.py @@ -329,14 +329,18 @@ def search_all( def generate_sso_configuration_link( self, tenant_id: str, - expire_time: int, + expire_time: Optional[int] = None, + email: Optional[str] = None, + sso_id: Optional[str] = None, ) -> str: """ Generate a tenant admin self-service link for SSO configuration. Args: - tenant_id (str): The ID of the tenant to generate the link for. - expire_time (int): The expiration duration in seconds. For a link valid for 6 hours, use 21600. + tenant_id (str): Tenant ID to generate the link for. + expire_time (int): Optional expiration duration in seconds. For a link valid for 6 hours, use 21600. + email (str): Optional email address associated with the admin. + sso_id (str): Optional SSO identifier for the tenant. Return value (str): Returns the admin SSO configuration link as a string. @@ -344,12 +348,17 @@ def generate_sso_configuration_link( Raise: AuthException: raised if generation operation fails """ + body: dict[str, Any] = {"tenantId": tenant_id} + if expire_time is not None: + body["expireTime"] = expire_time + if email is not None: + body["email"] = email + if sso_id is not None: + body["ssoId"] = sso_id + response = self._http.post( MgmtV1.tenant_generate_sso_configuration_link_path, - body={ - "tenantId": tenant_id, - "expireTime": expire_time, - }, + body=body, ) result = response.json() return result.get("adminSSOConfigurationLink", "") diff --git a/tests/management/test_tenant.py b/tests/management/test_tenant.py index 3d7e6eec4..429683dfc 100644 --- a/tests/management/test_tenant.py +++ b/tests/management/test_tenant.py @@ -663,3 +663,77 @@ def test_generate_sso_configuration_link_failed(self): "t1", 21600, ) + + def test_generate_sso_configuration_link_with_all_params(self): + client = DescopeClient( + self.dummy_project_id, + self.public_key_dict, + False, + self.dummy_management_key, + ) + + # Test success flow with all parameters + with patch("httpx.post") as mock_post: + network_resp = mock.Mock() + network_resp.is_success = True + network_resp.json.return_value = json.loads( + """{"adminSSOConfigurationLink": "https://example.com/sso-config-link"}""" + ) + mock_post.return_value = network_resp + link = client.mgmt.tenant.generate_sso_configuration_link( + tenant_id="t1", + expire_time=21600, + email="admin@example.com", + sso_id="sso123", + ) + self.assertEqual(link, "https://example.com/sso-config-link") + mock_post.assert_called_with( + f"{common.DEFAULT_BASE_URL}{MgmtV1.tenant_generate_sso_configuration_link_path}", + headers={ + **common.default_headers, + "Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}", + "x-descope-project-id": self.dummy_project_id, + }, + params=None, + json={ + "tenantId": "t1", + "expireTime": 21600, + "email": "admin@example.com", + "ssoId": "sso123", + }, + follow_redirects=False, + verify=SSLMatcher(), + timeout=DEFAULT_TIMEOUT_SECONDS, + ) + + def test_generate_sso_configuration_link_minimal_params(self): + client = DescopeClient( + self.dummy_project_id, + self.public_key_dict, + False, + self.dummy_management_key, + ) + + # Test success flow with only required parameter + with patch("httpx.post") as mock_post: + network_resp = mock.Mock() + network_resp.is_success = True + network_resp.json.return_value = json.loads( + """{"adminSSOConfigurationLink": "https://example.com/sso-config-link"}""" + ) + mock_post.return_value = network_resp + link = client.mgmt.tenant.generate_sso_configuration_link("t1") + self.assertEqual(link, "https://example.com/sso-config-link") + mock_post.assert_called_with( + f"{common.DEFAULT_BASE_URL}{MgmtV1.tenant_generate_sso_configuration_link_path}", + headers={ + **common.default_headers, + "Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}", + "x-descope-project-id": self.dummy_project_id, + }, + params=None, + json={"tenantId": "t1"}, + follow_redirects=False, + verify=SSLMatcher(), + timeout=DEFAULT_TIMEOUT_SECONDS, + )