Skip to content

Commit

Permalink
cherry-pick 3.0.1 fix on to 4.x
Browse files Browse the repository at this point in the history
ARCHBOM-1036
  • Loading branch information
robrap committed Mar 16, 2020
1 parent f28a9e6 commit cd7a92f
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 9 deletions.
2 changes: 1 addition & 1 deletion edx_rest_framework_extensions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
""" edx Django REST Framework extensions. """

__version__ = '4.0.3' # pragma: no cover
__version__ = '4.0.4' # pragma: no cover
4 changes: 2 additions & 2 deletions edx_rest_framework_extensions/auth/jwt/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

from edx_rest_framework_extensions.auth.jwt.constants import USE_JWT_COOKIE_HEADER
from edx_rest_framework_extensions.auth.jwt.decoder import jwt_decode_handler
from edx_rest_framework_extensions.auth.jwt.decoder import configured_jwt_decode_handler
from edx_rest_framework_extensions.settings import get_setting


Expand Down Expand Up @@ -187,4 +187,4 @@ def get_decoded_jwt_from_auth(request):
if not is_jwt_authenticated(request):
return None

return jwt_decode_handler(request.auth)
return configured_jwt_decode_handler(request.auth)
4 changes: 2 additions & 2 deletions edx_rest_framework_extensions/auth/jwt/cookies.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from django.conf import settings

from edx_rest_framework_extensions.auth.jwt.decoder import jwt_decode_handler
from edx_rest_framework_extensions.auth.jwt.decoder import configured_jwt_decode_handler


def jwt_cookie_name():
Expand All @@ -30,4 +30,4 @@ def get_decoded_jwt(request):

if not jwt_cookie:
return None
return jwt_decode_handler(jwt_cookie)
return configured_jwt_decode_handler(jwt_cookie)
21 changes: 18 additions & 3 deletions edx_rest_framework_extensions/auth/jwt/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ def jwt_decode_handler(token):
'JWT_PUBLIC_SIGNING_JWK_SET': 'the-jwk-set-of-public-signing-keys',
}
Warning:
Do **not** use this method internally. Only use it in ``JWT_DECODE_HANDLER`` like the above example.
Internally, use ``configured_jwt_decode_handler`` which respects the ``JWT_DECODE_HANDLER`` setting.
Args:
token (str): JWT to be decoded.
Expand All @@ -60,26 +64,37 @@ def jwt_decode_handler(token):
return _set_token_defaults(decoded_token)


def configured_jwt_decode_handler(token):
"""
Calls the ``jwt_decode_handler`` configured in the ``JWT_DECODE_HANDLER`` setting.
"""
api_setting_jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
return api_setting_jwt_decode_handler(token)


def decode_jwt_scopes(token):
"""
Decode the JWT and return the scopes claim.
"""
return jwt_decode_handler(token).get('scopes', [])
return configured_jwt_decode_handler(token).get('scopes', [])


def decode_jwt_is_restricted(token):
"""
Decode the JWT and return the is_restricted claim.
"""
return jwt_decode_handler(token)['is_restricted']
return configured_jwt_decode_handler(token).get('is_restricted', False)


def decode_jwt_filters(token):
"""
Decode the JWT, parse the filters claim, and return a
list of (filter_type, filter_value) tuples.
"""
return [jwt_filter.split(':') for jwt_filter in jwt_decode_handler(token)['filters']]
return [
jwt_filter.split(':')
for jwt_filter in configured_jwt_decode_handler(token).get('filters', [])
]


def _set_token_defaults(token):
Expand Down
70 changes: 69 additions & 1 deletion edx_rest_framework_extensions/auth/jwt/tests/test_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
from django.conf import settings
from django.test import TestCase, override_settings

from edx_rest_framework_extensions.auth.jwt.decoder import jwt_decode_handler
from edx_rest_framework_extensions.auth.jwt.decoder import (
decode_jwt_filters,
decode_jwt_is_restricted,
decode_jwt_scopes,
jwt_decode_handler,
)
from edx_rest_framework_extensions.auth.jwt.tests.utils import (
generate_jwt_token,
generate_latest_version_payload,
Expand Down Expand Up @@ -137,3 +142,66 @@ def test_upgrade(self):
# Keep time-related values constant for full-proof comparison.
upgraded_payload['iat'], upgraded_payload['exp'] = jwt_payload['iat'], jwt_payload['exp']
self.assertDictEqual(jwt_decode_handler(token), upgraded_payload)


def _jwt_decode_handler_with_defaults(token): # pylint: disable=unused-argument
"""
Accepts anything as a token and returns a fake JWT payload with defaults.
"""
return {
'scopes': ['fake:scope'],
'is_restricted': True,
'filters': ['fake:filter'],
}


def _jwt_decode_handler_no_defaults(token): # pylint: disable=unused-argument
"""
Accepts anything as a token and returns a fake JWT payload with no defaults.
"""
return {}


@ddt.ddt
class JWTDecodeHandlerSettingTests(TestCase):
"""
Tests to ensure utility functions respect JWT_DECODE_HANDLER setting.
Note: An attempt was made to use ``override_settings`` to actually set
``JWT_DECODE_HANDLER``, but clean-up of the tests in tearDown was not working,
even after reloading the module, and it was failing other tests in the test suite.
"""
NORMALLY_INVALID_TOKEN = 'this is a valid jwt only with fake_jwt_decode_handler'

@ddt.data(
('_jwt_decode_handler_with_defaults', ['fake:scope']),
('_jwt_decode_handler_no_defaults', [])
)
@ddt.unpack
@mock.patch('edx_rest_framework_extensions.auth.jwt.decoder.api_settings')
def test_decode_jwt_scopes(self, jwt_decode_handler_name, expected_scope, mock_api_settings):
mock_api_settings.JWT_DECODE_HANDLER = globals()[jwt_decode_handler_name]
scopes = decode_jwt_scopes(self.NORMALLY_INVALID_TOKEN)
self.assertEqual(scopes, expected_scope)

@ddt.data(
('_jwt_decode_handler_with_defaults', True),
('_jwt_decode_handler_no_defaults', False)
)
@ddt.unpack
@mock.patch('edx_rest_framework_extensions.auth.jwt.decoder.api_settings')
def test_decode_jwt_is_restricted(self, jwt_decode_handler_name, expected_is_restricted, mock_api_settings):
mock_api_settings.JWT_DECODE_HANDLER = globals()[jwt_decode_handler_name]
is_restricted = decode_jwt_is_restricted(self.NORMALLY_INVALID_TOKEN)
self.assertEqual(is_restricted, expected_is_restricted)

@ddt.data(
('_jwt_decode_handler_with_defaults', [['fake', 'filter']]),
('_jwt_decode_handler_no_defaults', [])
)
@ddt.unpack
@mock.patch('edx_rest_framework_extensions.auth.jwt.decoder.api_settings')
def test_decode_jwt_filters(self, jwt_decode_handler_name, expected_filter, mock_api_settings):
mock_api_settings.JWT_DECODE_HANDLER = globals()[jwt_decode_handler_name]
filters = decode_jwt_filters(self.NORMALLY_INVALID_TOKEN)
self.assertEqual(filters, expected_filter)

0 comments on commit cd7a92f

Please sign in to comment.