Skip to content

Commit

Permalink
feat: add check for enforcing jwt and lms user email match
Browse files Browse the repository at this point in the history
  • Loading branch information
syedsajjadkazmii committed Dec 20, 2023
1 parent c82ad02 commit 5719a80
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
42 changes: 42 additions & 0 deletions edx_rest_framework_extensions/auth/jwt/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from edx_rest_framework_extensions.config import (
ENABLE_SET_REQUEST_USER_FOR_JWT_COOKIE,
VERIFY_LMS_USER_ID_PROPERTY_NAME,
ENABLE_JWT_AND_LMS_USER_EMAIL_MATCH,
)
from edx_rest_framework_extensions.settings import get_setting

Expand All @@ -34,6 +35,10 @@ class JwtSessionUserMismatchError(JwtAuthenticationError):
pass


class JwtUserEmailMismatchError(JwtAuthenticationError):
pass


class CSRFCheck(CsrfViewMiddleware):
def _reject(self, request, reason):
# Return the failure reason instead of an HttpResponse
Expand Down Expand Up @@ -96,6 +101,8 @@ def authenticate(self, request):
# 'user-mismatch-enforced-failure': JWT vs session user mismatch found for what would
# have been a successful JWT authentication, but we are enforcing a match, and thus
# we fail authentication.
# 'user-email-mismatch-failure': JWT vs lms user email mismatch found.


is_authenticating_with_jwt_cookie = self.is_authenticating_with_jwt_cookie(request)
try:
Expand All @@ -106,6 +113,20 @@ def authenticate(self, request):
set_custom_attribute('jwt_auth_result', 'n/a')
return user_and_auth

lms_user_id_property_name = get_setting(VERIFY_LMS_USER_ID_PROPERTY_NAME)
# Check lms_user_id_property_name to be 'id' to make this check work for LMS only
if lms_user_id_property_name == 'id':
user, auth = user_and_auth
is_email_mismatch = self._is_jwt_and_lms_user_email_mismatch(request, user)
if is_email_mismatch and get_setting(ENABLE_JWT_AND_LMS_USER_EMAIL_MATCH):
set_custom_attribute('jwt_auth_result', 'user-email-mismatch-failure')
raise JwtUserEmailMismatchError(
'Failing JWT authentication due to jwt user email mismatch '
'with lms user email.'
)
elif is_email_mismatch:
set_custom_attribute('jwt_auth_result', 'user-email-mismatch-failure')

# Not using JWT cookie, CSRF validation not required
if not is_authenticating_with_jwt_cookie:
set_custom_attribute('jwt_auth_result', 'success-auth-header')
Expand Down Expand Up @@ -305,6 +326,27 @@ def _is_jwt_cookie_and_session_user_mismatch(self, request):

return True

def _is_jwt_and_lms_user_email_mismatch(self, request, user):
"""
Returns True if user email in JWT and email of user do not match, False otherwise.
Arguments:
request: The request.
user: user from user_and_auth
"""
lms_user_email = getattr(user, 'email', None)

# This function will check for token in the authorization header and return it
# otherwise it will return token from JWT cookies.
token = JSONWebTokenAuthentication.get_token_from_request(request)
decoded_jwt = configured_jwt_decode_handler(token)
jwt_user_email = decoded_jwt.get('email', None)

if lms_user_email != jwt_user_email:
return True

return False

def _get_and_monitor_jwt_cookie_lms_user_id(self, request):
"""
Returns the LMS user id from the JWT cookie, or None if not found
Expand Down
10 changes: 10 additions & 0 deletions edx_rest_framework_extensions/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@
# .. toggle_tickets: ARCH-1210, ARCH-1199, ARCH-1197
ENABLE_SET_REQUEST_USER_FOR_JWT_COOKIE = 'ENABLE_SET_REQUEST_USER_FOR_JWT_COOKIE'

# .. toggle_name: EDX_DRF_EXTENSIONS[ENABLE_JWT_AND_LMS_USER_EMAIL_MATCH]
# .. toggle_implementation: DjangoSetting
# .. toggle_default: False
# .. toggle_description: Toggle to add a check for matching user email in JWT and LMS user email
# for authentication in JwtAuthentication class.
# .. toggle_use_cases: temporary
# .. toggle_creation_date: 2023-12-20
# .. toggle_tickets: VAN-1964
ENABLE_JWT_AND_LMS_USER_EMAIL_MATCH = 'ENABLE_JWT_AND_LMS_USER_EMAIL_MATCH'

# .. setting_name: EDX_DRF_EXTENSIONS[VERIFY_LMS_USER_ID_PROPERTY_NAME]
# .. setting_default: None ('lms_user_id' if found)
# .. setting_description: This setting should be set to the name of the user object property containing the LMS
Expand Down
2 changes: 2 additions & 0 deletions edx_rest_framework_extensions/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from edx_rest_framework_extensions.config import (
ENABLE_SET_REQUEST_USER_FOR_JWT_COOKIE,
VERIFY_LMS_USER_ID_PROPERTY_NAME,
ENABLE_JWT_AND_LMS_USER_EMAIL_MATCH,
)


Expand All @@ -26,6 +27,7 @@

DEFAULT_SETTINGS = {
ENABLE_SET_REQUEST_USER_FOR_JWT_COOKIE: False,
ENABLE_JWT_AND_LMS_USER_EMAIL_MATCH: False,

'JWT_PAYLOAD_MERGEABLE_USER_ATTRIBUTES': (),
# Map JWT claims to user attributes.
Expand Down

0 comments on commit 5719a80

Please sign in to comment.