feat: allow for forcing asymmetric jwts (#32045)

Add a temporary feature toggle to force the LMS to
only produce asymmetric JWTs. This is a part of
DEPR of Symmetric JWTs:
https://github.com/openedx/public-engineering/issues/83
This commit is contained in:
Robert Raposa
2023-04-10 14:46:44 -04:00
committed by GitHub
parent 1e35bc10eb
commit 6cae1fa429
2 changed files with 30 additions and 1 deletions

View File

@@ -6,8 +6,9 @@ import logging
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

View File

@@ -73,6 +73,11 @@ class TestCreateJWTs(AccessTokenMixin, TestCase):
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)