diff --git a/openedx/core/djangoapps/oauth_dispatch/jwt.py b/openedx/core/djangoapps/oauth_dispatch/jwt.py index feabcaa13aa7..329d28822fca 100644 --- a/openedx/core/djangoapps/oauth_dispatch/jwt.py +++ b/openedx/core/djangoapps/oauth_dispatch/jwt.py @@ -6,8 +6,9 @@ from time import time from django.conf import settings -from edx_django_utils.monitoring import set_custom_attribute +from edx_django_utils.monitoring import increment, set_custom_attribute from edx_rbac.utils import create_role_auth_claim_for_user +from edx_toggles.toggles import SettingToggle from jwkest import jwk from jwkest.jws import JWS @@ -159,6 +160,12 @@ def _create_jwt( secret (string): Overrides configured JWT secret (signing) key. """ use_asymmetric_key = _get_use_asymmetric_key_value(is_restricted, use_asymmetric_key) + # Enable monitoring of key type used. Use increment in case there are multiple calls in a transaction. + if use_asymmetric_key: + increment('create_asymmetric_jwt_count') + else: + increment('create_symmetric_jwt_count') + # Default scopes should only contain non-privileged data. # Do not be misled by the fact that `email` and `profile` are default scopes. They # were included for legacy compatibility, even though they contain privileged data. @@ -188,10 +195,27 @@ def _create_jwt( return _encode_and_sign(payload, use_asymmetric_key, secret) +# .. toggle_name: JWT_AUTH_FORCE_CREATE_ASYMMETRIC +# .. toggle_implementation: SettingToggle +# .. toggle_default: False +# .. toggle_description: When True, forces the LMS to only create JWTs signed with the asymmetric +# key. This is a temporary rollout toggle for DEPR of symmetric JWTs. +# .. toggle_use_cases: temporary +# .. toggle_creation_date: 2023-04-10 +# .. toggle_target_removal_date: 2023-07-31 +# .. toggle_tickets: https://github.com/openedx/public-engineering/issues/83 +JWT_AUTH_FORCE_CREATE_ASYMMETRIC = SettingToggle( + 'JWT_AUTH_FORCE_CREATE_ASYMMETRIC', default=False, module_name=__name__ +) + + def _get_use_asymmetric_key_value(is_restricted, use_asymmetric_key): """ Returns the value to use for use_asymmetric_key. """ + if JWT_AUTH_FORCE_CREATE_ASYMMETRIC.is_enabled(): + return True + return use_asymmetric_key or is_restricted diff --git a/openedx/core/djangoapps/oauth_dispatch/tests/test_jwt.py b/openedx/core/djangoapps/oauth_dispatch/tests/test_jwt.py index d4cbe860541e..abacfe6bee8a 100644 --- a/openedx/core/djangoapps/oauth_dispatch/tests/test_jwt.py +++ b/openedx/core/djangoapps/oauth_dispatch/tests/test_jwt.py @@ -73,6 +73,11 @@ def test_dot_create_jwt_for_token_with_asymmetric(self): jwt_token = self._create_jwt_for_token(DOTAdapter(), use_asymmetric_key=True) self._assert_jwt_is_valid(jwt_token, should_be_asymmetric_key=True) + @override_settings(JWT_AUTH_FORCE_CREATE_ASYMMETRIC=True) + def test_dot_create_jwt_for_token_forced_asymmetric(self): + jwt_token = self._create_jwt_for_token(DOTAdapter(), use_asymmetric_key=False) + self._assert_jwt_is_valid(jwt_token, should_be_asymmetric_key=True) + def test_create_jwt_for_token_default_expire_seconds(self): oauth_adapter = DOTAdapter() jwt_token = self._create_jwt_for_token(oauth_adapter, use_asymmetric_key=False)