From 2ad8b1b09a95b3103104690f15a9a762a26b08fc Mon Sep 17 00:00:00 2001 From: rishabhpoddar Date: Sat, 12 Oct 2024 18:56:46 +0530 Subject: [PATCH] fixe stuff --- .../create_or_update_third_party_config.py | 2 +- .../multitenancy/get_third_party_config.py | 6 ++- .../recipe/multitenancy/interfaces.py | 38 ++++++++++++++++--- .../multitenancy/recipe_implementation.py | 26 ++++++------- .../recipe/passwordless/recipe.py | 8 +--- .../thirdparty/providers/active_directory.py | 10 ++--- .../recipe/thirdparty/providers/discord.py | 2 +- tests/test-server/app.py | 5 ++- tests/test-server/multitenancy.py | 15 +++++--- tests/test-server/thirdparty.py | 20 ++++++++++ 10 files changed, 91 insertions(+), 41 deletions(-) diff --git a/supertokens_python/recipe/dashboard/api/multitenancy/create_or_update_third_party_config.py b/supertokens_python/recipe/dashboard/api/multitenancy/create_or_update_third_party_config.py index 32f403a8..eb6ac3fb 100644 --- a/supertokens_python/recipe/dashboard/api/multitenancy/create_or_update_third_party_config.py +++ b/supertokens_python/recipe/dashboard/api/multitenancy/create_or_update_third_party_config.py @@ -155,7 +155,7 @@ async def handle_create_or_update_third_party_config( provider_config["clients"][0]["clientSecret"] = resp["clientSecret"] third_party_res = await create_or_update_third_party_config( - tenant_id, provider_config, None, user_context + tenant_id, ProviderConfig.from_json(provider_config), None, user_context ) return CreateOrUpdateThirdPartyConfigOkResult(third_party_res.created_new) diff --git a/supertokens_python/recipe/dashboard/api/multitenancy/get_third_party_config.py b/supertokens_python/recipe/dashboard/api/multitenancy/get_third_party_config.py index 375e3f06..ef050343 100644 --- a/supertokens_python/recipe/dashboard/api/multitenancy/get_third_party_config.py +++ b/supertokens_python/recipe/dashboard/api/multitenancy/get_third_party_config.py @@ -61,8 +61,10 @@ def to_json(self) -> Dict[str, Any]: "isExchangeAuthCodeForOAuthTokensOverridden" ] = self.is_exchange_auth_code_for_oauth_tokens_overridden json_response["isGetUserInfoOverridden"] = self.is_get_user_info_overridden - json_response["status"] = "OK" - return json_response + return { + "status": "OK", + "providerConfig": json_response, + } class GetThirdPartyConfigUnknownTenantError(APIResponse): diff --git a/supertokens_python/recipe/multitenancy/interfaces.py b/supertokens_python/recipe/multitenancy/interfaces.py index 52e66b3f..af65930f 100644 --- a/supertokens_python/recipe/multitenancy/interfaces.py +++ b/supertokens_python/recipe/multitenancy/interfaces.py @@ -62,19 +62,45 @@ class TenantConfigCreateOrUpdate: def __init__( self, core_config: Dict[str, Any] = {}, - first_factors: Optional[List[str]] = None, - required_secondary_factors: Optional[List[str]] = None, + first_factors: Optional[List[str]] = [ + "NO_CHANGE" + ], # A default value here means that if the user does not set this, it will not make any change in the core + required_secondary_factors: Optional[List[str]] = [ + "NO_CHANGE" + ], # A default value here means that if the user does not set this, it will not make any change in the core ): self.core_config = core_config - self.first_factors = first_factors - self.required_secondary_factors = required_secondary_factors + self._first_factors = first_factors + self._required_secondary_factors = required_secondary_factors + + def is_first_factors_unchanged(self) -> bool: + return self._first_factors == ["NO_CHANGE"] + + def is_required_secondary_factors_unchanged(self) -> bool: + return self._required_secondary_factors == ["NO_CHANGE"] + + def get_first_factors_for_update(self) -> Optional[List[str]]: + if self._first_factors == ["NO_CHANGE"]: + raise Exception( + "First check if the value of first_factors is not NO_CHANGE" + ) + return self._first_factors + + def get_required_secondary_factors_for_update(self) -> Optional[List[str]]: + if self._required_secondary_factors == ["NO_CHANGE"]: + raise Exception( + "First check if the value of required_secondary_factors is not NO_CHANGE" + ) + return self._required_secondary_factors @staticmethod def from_json(json: Dict[str, Any]) -> TenantConfigCreateOrUpdate: return TenantConfigCreateOrUpdate( core_config=json.get("coreConfig", {}), - first_factors=json.get("firstFactors", []), - required_secondary_factors=json.get("requiredSecondaryFactors", []), + first_factors=json.get("firstFactors", ["NO_CHANGE"]), + required_secondary_factors=json.get( + "requiredSecondaryFactors", ["NO_CHANGE"] + ), ) diff --git a/supertokens_python/recipe/multitenancy/recipe_implementation.py b/supertokens_python/recipe/multitenancy/recipe_implementation.py index c60f148f..90578bac 100644 --- a/supertokens_python/recipe/multitenancy/recipe_implementation.py +++ b/supertokens_python/recipe/multitenancy/recipe_implementation.py @@ -132,21 +132,21 @@ async def create_or_update_tenant( config: Optional[TenantConfigCreateOrUpdate], user_context: Dict[str, Any], ) -> CreateOrUpdateTenantOkResult: + json_body: Dict[str, Any] = { + "tenantId": tenant_id, + } + if config is not None: + if not config.is_first_factors_unchanged(): + json_body["firstFactors"] = config.get_first_factors_for_update() + if not config.is_required_secondary_factors_unchanged(): + json_body[ + "requiredSecondaryFactors" + ] = config.get_required_secondary_factors_for_update() + json_body["coreConfig"] = config.core_config + response = await self.querier.send_put_request( NormalisedURLPath("/recipe/multitenancy/tenant/v2"), - { - "tenantId": tenant_id, - "firstFactors": ( - config.first_factors - if config and config.first_factors is not None - else None - ), - "requiredSecondaryFactors": ( - config.required_secondary_factors - if config and config.required_secondary_factors is not None - else None - ), - }, + json_body, user_context=user_context, ) return CreateOrUpdateTenantOkResult( diff --git a/supertokens_python/recipe/passwordless/recipe.py b/supertokens_python/recipe/passwordless/recipe.py index af01c88a..ae0e752e 100644 --- a/supertokens_python/recipe/passwordless/recipe.py +++ b/supertokens_python/recipe/passwordless/recipe.py @@ -72,6 +72,7 @@ from .utils import ( ContactConfig, OverrideConfig, + get_enabled_pwless_factors, validate_and_normalise_user_input, ) from ...post_init_callbacks import PostSTInitCallbacks @@ -155,12 +156,7 @@ def __init__( def callback(): mfa_instance = MultiFactorAuthRecipe.get_instance() - all_factors = [ - FactorIds.OTP_EMAIL, - FactorIds.LINK_EMAIL, - FactorIds.OTP_PHONE, - FactorIds.LINK_PHONE, - ] + all_factors = get_enabled_pwless_factors(self.config) if mfa_instance is not None: async def f1(_: TenantConfig): diff --git a/supertokens_python/recipe/thirdparty/providers/active_directory.py b/supertokens_python/recipe/thirdparty/providers/active_directory.py index 2a4476a9..8ebb00bc 100644 --- a/supertokens_python/recipe/thirdparty/providers/active_directory.py +++ b/supertokens_python/recipe/thirdparty/providers/active_directory.py @@ -30,13 +30,11 @@ async def get_config_for_client_type( config = await super().get_config_for_client_type(client_type, user_context) if ( - config.additional_config is None - or config.additional_config.get("directoryId") is None + config.additional_config is not None + and config.additional_config.get("directoryId") is not None ): - if not config.oidc_discovery_endpoint: - raise Exception( - "Please provide the directoryId in the additionalConfig of the Active Directory provider." - ) + config.oidc_discovery_endpoint = f"https://login.microsoftonline.com/{config.additional_config['directoryId']}/v2.0/.well-known/openid-configuration" + if config.oidc_discovery_endpoint is not None: config.oidc_discovery_endpoint = ( normalise_oidc_endpoint_to_include_well_known( diff --git a/supertokens_python/recipe/thirdparty/providers/discord.py b/supertokens_python/recipe/thirdparty/providers/discord.py index 677f3803..d301cbcb 100644 --- a/supertokens_python/recipe/thirdparty/providers/discord.py +++ b/supertokens_python/recipe/thirdparty/providers/discord.py @@ -45,7 +45,7 @@ def Discord(input: ProviderInput) -> Provider: # pylint: disable=redefined-buil input.config.name = "Discord" if not input.config.authorization_endpoint: - input.config.authorization_endpoint = "https://discord.com/api/oauth2/authorize" + input.config.authorization_endpoint = "https://discord.com/oauth2/authorize" if not input.config.token_endpoint: input.config.token_endpoint = "https://discord.com/api/oauth2/token" diff --git a/tests/test-server/app.py b/tests/test-server/app.py index 5667bc2d..559fe2b6 100644 --- a/tests/test-server/app.py +++ b/tests/test-server/app.py @@ -7,6 +7,7 @@ from supertokens_python.ingredients.smsdelivery.types import SMSDeliveryConfig from supertokens_python.recipe import ( accountlinking, + dashboard, multifactorauth, passwordless, totp, @@ -225,7 +226,9 @@ def init_st(config: Dict[str, Any]): st_reset() override_logging.reset_override_logs() - recipe_list: List[Callable[[AppInfo], RecipeModule]] = [] + recipe_list: List[Callable[[AppInfo], RecipeModule]] = [ + dashboard.init(api_key="test") + ] for recipe_config in config.get("recipeList", []): recipe_id = recipe_config.get("recipeId") if recipe_id == "emailpassword": diff --git a/tests/test-server/multitenancy.py b/tests/test-server/multitenancy.py index b617722f..c7ee4c76 100644 --- a/tests/test-server/multitenancy.py +++ b/tests/test-server/multitenancy.py @@ -20,13 +20,18 @@ def create_or_update_tenant(): # type: ignore if data is None: return jsonify({"status": "MISSING_DATA_ERROR"}) tenant_id = data["tenantId"] - config = data["config"] user_context = data.get("userContext") - config = TenantConfigCreateOrUpdate( - first_factors=config.get("firstFactors"), - required_secondary_factors=config.get("requiredSecondaryFactors"), - core_config=config.get("coreConfig"), + config = ( + TenantConfigCreateOrUpdate( + first_factors=data["config"].get("firstFactors"), + required_secondary_factors=data["config"].get( + "requiredSecondaryFactors" + ), + core_config=data["config"].get("coreConfig", {}), + ) + if "config" in data + else None ) response = multitenancy.create_or_update_tenant(tenant_id, config, user_context) diff --git a/tests/test-server/thirdparty.py b/tests/test-server/thirdparty.py index dfc0ff00..513fd5a6 100644 --- a/tests/test-server/thirdparty.py +++ b/tests/test-server/thirdparty.py @@ -68,3 +68,23 @@ def thirdpartymanuallycreateorupdate(): # type: ignore "reason": response.reason, } ) + + @app.route("/test/thirdparty/getprovider", methods=["POST"]) # type: ignore + def get_provider(): # type: ignore + data = request.get_json() + if data is None: + return jsonify({"status": "MISSING_DATA_ERROR"}) + + tenant_id = data.get("tenantId", "public") + third_party_id = data["thirdPartyId"] + client_type = data.get("clientType", None) + user_context = data.get("userContext", {}) + + from supertokens_python.recipe.thirdparty.syncio import get_provider + + provider = get_provider(tenant_id, third_party_id, client_type, user_context) + + if provider is None: + return jsonify({}) + + return jsonify({"id": provider.id, "config": provider.config.to_json()})