From ddf1a6cabd9f7e06d17d90f45a6affe95c281b2a Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 12 Sep 2023 14:39:53 +0530 Subject: [PATCH 1/4] fix: ignore protected props in create_new_session functions --- supertokens_python/recipe/session/asyncio/__init__.py | 5 +++++ supertokens_python/recipe/session/constants.py | 1 + .../recipe/session/recipe_implementation.py | 8 +++++++- .../recipe/session/session_request_functions.py | 5 +++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/supertokens_python/recipe/session/asyncio/__init__.py b/supertokens_python/recipe/session/asyncio/__init__.py index c9a6a4b25..a50422885 100644 --- a/supertokens_python/recipe/session/asyncio/__init__.py +++ b/supertokens_python/recipe/session/asyncio/__init__.py @@ -41,6 +41,7 @@ get_session_from_request, refresh_session_in_request, ) +from ..constants import protected_props from ..utils import get_required_claim_validators from supertokens_python.recipe.multitenancy.constants import DEFAULT_TENANT_ID @@ -106,6 +107,10 @@ async def create_new_session_without_request_response( final_access_token_payload = {**access_token_payload, "iss": issuer} + for prop in protected_props: + if prop in final_access_token_payload: + del final_access_token_payload[prop] + for claim in claims_added_by_other_recipes: update = await claim.build(user_id, tenant_id, user_context) final_access_token_payload = {**final_access_token_payload, **update} diff --git a/supertokens_python/recipe/session/constants.py b/supertokens_python/recipe/session/constants.py index 83b739651..49c634fac 100644 --- a/supertokens_python/recipe/session/constants.py +++ b/supertokens_python/recipe/session/constants.py @@ -42,5 +42,6 @@ "parentRefreshTokenHash1", "refreshTokenHash1", "antiCsrfToken", + "rsub", "tId", ] diff --git a/supertokens_python/recipe/session/recipe_implementation.py b/supertokens_python/recipe/session/recipe_implementation.py index f487dcb56..a9f9aad6d 100644 --- a/supertokens_python/recipe/session/recipe_implementation.py +++ b/supertokens_python/recipe/session/recipe_implementation.py @@ -47,6 +47,7 @@ from supertokens_python import AppInfo from .interfaces import SessionContainer +from .constants import protected_props from supertokens_python.querier import Querier from supertokens_python.recipe.multitenancy.constants import DEFAULT_TENANT_ID @@ -378,8 +379,13 @@ async def merge_into_access_token_payload( if session_info is None: return False + new_access_token_payload = session_info.custom_claims_in_access_token_payload + for k in protected_props: + if k in new_access_token_payload: + del new_access_token_payload[k] + new_access_token_payload = { - **session_info.custom_claims_in_access_token_payload, + **new_access_token_payload, **access_token_payload_update, } for k in access_token_payload_update.keys(): diff --git a/supertokens_python/recipe/session/session_request_functions.py b/supertokens_python/recipe/session/session_request_functions.py index 3bf3fc5ee..104ae4504 100644 --- a/supertokens_python/recipe/session/session_request_functions.py +++ b/supertokens_python/recipe/session/session_request_functions.py @@ -60,6 +60,7 @@ set_request_in_user_context_if_not_defined, ) from supertokens_python.supertokens import Supertokens +from .constants import protected_props if TYPE_CHECKING: from supertokens_python.recipe.session.recipe import SessionRecipe @@ -240,6 +241,10 @@ async def create_new_session_in_request( final_access_token_payload = {**access_token_payload, "iss": issuer} + for prop in protected_props: + if prop in final_access_token_payload: + del final_access_token_payload[prop] + for claim in claims_added_by_other_recipes: update = await claim.build(user_id, tenant_id, user_context) final_access_token_payload = {**final_access_token_payload, **update} From 97e219c0f3389d7444b645448d4e5505373759a4 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 12 Sep 2023 14:42:40 +0530 Subject: [PATCH 2/4] chores: Bump python version and update CHANGELOG --- CHANGELOG.md | 5 +++++ setup.py | 2 +- supertokens_python/constants.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78271cd16..3e4aa70f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] + +## [0.16.0] - 2023-09-13 + + ### Added - The Dashboard recipe now accepts a new `admins` property which can be used to give Dashboard Users write privileges for the user dashboard. @@ -15,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changes - Dashboard APIs now return a status code `403` for all non-GET requests if the currently logged in Dashboard User is not listed in the `admins` array +- Now ignoring protected props in the payload in `create_new_session` and `create_new_session_without_request_response` ## [0.15.3] - 2023-09-24 diff --git a/setup.py b/setup.py index 773b7148b..ca2400964 100644 --- a/setup.py +++ b/setup.py @@ -70,7 +70,7 @@ setup( name="supertokens_python", - version="0.15.3", + version="0.16.0", author="SuperTokens", license="Apache 2.0", author_email="team@supertokens.com", diff --git a/supertokens_python/constants.py b/supertokens_python/constants.py index 902c982ea..075ff9309 100644 --- a/supertokens_python/constants.py +++ b/supertokens_python/constants.py @@ -14,7 +14,7 @@ from __future__ import annotations SUPPORTED_CDI_VERSIONS = ["3.0"] -VERSION = "0.15.3" +VERSION = "0.16.0" TELEMETRY = "/telemetry" USER_COUNT = "/users/count" USER_DELETE = "/user/remove" From aa82dbc040c29162df8332fe16797a432fed79e6 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 12 Sep 2023 15:31:45 +0530 Subject: [PATCH 3/4] test: Add test for ignore protected props in create session --- tests/sessions/test_access_token_version.py | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/sessions/test_access_token_version.py b/tests/sessions/test_access_token_version.py index acfb5c269..6e4fe68e2 100644 --- a/tests/sessions/test_access_token_version.py +++ b/tests/sessions/test_access_token_version.py @@ -203,6 +203,29 @@ async def test_should_validate_v3_tokens_with_check_database_enabled(app: TestCl } +async def test_ignore_protected_props_in_create_session(app: TestClient): + init(**get_st_init_args([session.init()])) # type:ignore + start_st() + + create_session_res = app.post("/create", data={"sub": "asdf"}) + + assert create_session_res.status_code == 200 + + info = extract_info(create_session_res) + assert info["accessTokenFromAny"] is not None + assert info["refreshTokenFromAny"] is not None + assert info["frontToken"] is not None + + parsed_token = parse_jwt_without_signature_verification(info["accessTokenFromAny"]) + assert parsed_token.payload["sub"] != "asdf" + + s = await create_new_session_without_request_response( + "public", "user-id", {"sub": "asdf"} + ) + payload = parse_jwt_without_signature_verification(s.access_token).payload + assert payload["sub"] != "asdf" + + async def test_validation_logic_with_keys_that_can_use_json_nulls_values_in_claims(): """We want to make sure that for access token claims that can be null, the SDK does not fail access token validation if the core does not send them as part of the payload. For this we verify that validation passes when the keys are None, empty, From a51d242489e4f0d013937a9d3bf04881b4232981 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 12 Sep 2023 15:56:40 +0530 Subject: [PATCH 4/4] test: Update tests --- tests/sessions/test_access_token_version.py | 30 ++++++++++----------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/tests/sessions/test_access_token_version.py b/tests/sessions/test_access_token_version.py index 6e4fe68e2..244deb484 100644 --- a/tests/sessions/test_access_token_version.py +++ b/tests/sessions/test_access_token_version.py @@ -203,27 +203,25 @@ async def test_should_validate_v3_tokens_with_check_database_enabled(app: TestCl } -async def test_ignore_protected_props_in_create_session(app: TestClient): - init(**get_st_init_args([session.init()])) # type:ignore +async def test_ignore_protected_props_in_create_session(): + init(**get_st_init_args([session.init()])) start_st() - create_session_res = app.post("/create", data={"sub": "asdf"}) - - assert create_session_res.status_code == 200 - - info = extract_info(create_session_res) - assert info["accessTokenFromAny"] is not None - assert info["refreshTokenFromAny"] is not None - assert info["frontToken"] is not None - - parsed_token = parse_jwt_without_signature_verification(info["accessTokenFromAny"]) - assert parsed_token.payload["sub"] != "asdf" - s = await create_new_session_without_request_response( - "public", "user-id", {"sub": "asdf"} + "public", + "user1", + {"foo": "bar"}, ) payload = parse_jwt_without_signature_verification(s.access_token).payload - assert payload["sub"] != "asdf" + assert payload["foo"] == "bar" + assert payload["sub"] == "user1" + + s2 = await create_new_session_without_request_response( + "public", "user2", s.get_access_token_payload() + ) + payload = parse_jwt_without_signature_verification(s2.access_token).payload + assert payload["foo"] == "bar" + assert payload["sub"] == "user2" async def test_validation_logic_with_keys_that_can_use_json_nulls_values_in_claims():