Merge pull request #34400 from openedx/add-JWT-kid-for-verification-when-use-asymmetric-key

feat: add kid when encoding and signing JWT with asymmetric key
This commit is contained in:
Ben Lu
2024-04-08 12:53:49 -05:00
committed by GitHub
2 changed files with 43 additions and 0 deletions

View File

@@ -276,6 +276,19 @@ def _attach_profile_claim(payload, user):
'superuser': user.is_superuser,
})
# .. toggle_name: JWT_AUTH_ADD_KID_HEADER
# .. toggle_implementation: SettingToggle
# .. toggle_default: False
# .. toggle_description: When True, add KID header to JWT using asymmetrical key.
# .. toggle_use_cases: temporary
# .. toggle_creation_date: 2024-03-20
# .. toggle_target_removal_date: 2024-04-20
# .. toggle_tickets:
# https://2u-internal.atlassian.net/browse/AUTH-195?atlOrigin=eyJpIjoiODMzODBiODMwMjU5NGRiZTkyOTIzYThhZjZiNWE0MzMiLCJwIjoiaiJ9
JWT_AUTH_ADD_KID_HEADER = SettingToggle(
'JWT_AUTH_ADD_KID_HEADER', default=False, module_name=__name__
)
def _encode_and_sign(payload, use_asymmetric_key, secret):
"""Encode and sign the provided payload."""
@@ -289,6 +302,9 @@ def _encode_and_sign(payload, use_asymmetric_key, secret):
algorithm = settings.JWT_AUTH['JWT_ALGORITHM']
jwk = PyJWK(key, algorithm)
if JWT_AUTH_ADD_KID_HEADER.is_enabled() and jwk.key_id:
return jwt.encode(payload, jwk.key, algorithm=algorithm, headers={'kid': jwk.key_id})
return jwt.encode(payload, jwk.key, algorithm=algorithm)

View File

@@ -79,6 +79,33 @@ class TestCreateJWTs(AccessTokenMixin, TestCase):
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_kid_not_in_jwt_header_with_symmetric_key_and_kid_disabled(self):
jwt_token = self._create_jwt_for_token(DOTAdapter(), use_asymmetric_key=False)
header = jwt_api.jwt.get_unverified_header(jwt_token)
assert 'kid' not in header
self._assert_jwt_is_valid(jwt_token, should_be_asymmetric_key=False)
def test_kid_not_in_jwt_header_with_asymmetric_key_and_kid_disabled(self):
jwt_token = self._create_jwt_for_token(DOTAdapter(), use_asymmetric_key=True)
header = jwt_api.jwt.get_unverified_header(jwt_token)
assert 'kid' not in header
self._assert_jwt_is_valid(jwt_token, should_be_asymmetric_key=True)
@override_settings(JWT_AUTH_ADD_KID_HEADER=True)
def test_kid_not_in_jwt_header_with_symmetric_key_and_kid_enabled(self):
jwt_token = self._create_jwt_for_token(DOTAdapter(), use_asymmetric_key=False)
header = jwt_api.jwt.get_unverified_header(jwt_token)
assert 'kid' not in header
self._assert_jwt_is_valid(jwt_token, should_be_asymmetric_key=False)
@override_settings(JWT_AUTH_ADD_KID_HEADER=True)
def test_kid_in_jwt_header_with_asymmetric_key_and_kid_enabled(self):
jwt_token = self._create_jwt_for_token(DOTAdapter(), use_asymmetric_key=True)
header = jwt_api.jwt.get_unverified_header(jwt_token)
assert 'kid' in header
assert header['kid'] == 'BTZ9HA6K'
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)