Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow for forcing asymmetric jwts #32045

Merged
merged 4 commits into from
Apr 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion openedx/core/djangoapps/oauth_dispatch/jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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


Expand Down
5 changes: 5 additions & 0 deletions openedx/core/djangoapps/oauth_dispatch/tests/test_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down