JWT authentication updates
- Using jwt_decode_handler from edx-drf-extensions - Updated djangorestframework-jwt - Removed feature flag around JWT auth ECOM-4221
This commit is contained in:
committed by
Clinton Blackburn
parent
b6d5c614dd
commit
5a7bc01986
@@ -2118,14 +2118,16 @@ SOCIAL_MEDIA_FOOTER_NAMES = [
|
||||
|
||||
# JWT Settings
|
||||
JWT_AUTH = {
|
||||
'JWT_SECRET_KEY': None,
|
||||
# TODO Set JWT_SECRET_KEY to a secure value. By default, SECRET_KEY will be used.
|
||||
# 'JWT_SECRET_KEY': '',
|
||||
'JWT_ALGORITHM': 'HS256',
|
||||
'JWT_VERIFY_EXPIRATION': True,
|
||||
'JWT_ISSUER': None,
|
||||
'JWT_PAYLOAD_GET_USERNAME_HANDLER': lambda d: d.get('username'),
|
||||
# TODO Set JWT_ISSUER and JWT_AUDIENCE to values specific to your service/organization.
|
||||
'JWT_ISSUER': 'change-me',
|
||||
'JWT_AUDIENCE': None,
|
||||
'JWT_PAYLOAD_GET_USERNAME_HANDLER': lambda d: d.get('username'),
|
||||
'JWT_LEEWAY': 1,
|
||||
'JWT_DECODE_HANDLER': 'openedx.core.lib.api.jwt_decode_handler.decode',
|
||||
'JWT_DECODE_HANDLER': 'edx_rest_framework_extensions.utils.jwt_decode_handler',
|
||||
}
|
||||
|
||||
# The footer URLs dictionary maps social footer names
|
||||
@@ -2225,14 +2227,6 @@ if FEATURES.get('CLASS_DASHBOARD'):
|
||||
ENABLE_CREDIT_ELIGIBILITY = True
|
||||
FEATURES['ENABLE_CREDIT_ELIGIBILITY'] = ENABLE_CREDIT_ELIGIBILITY
|
||||
|
||||
################ Enable JWT auth ####################
|
||||
# When this feature flag is set to False, API endpoints using
|
||||
# JSONWebTokenAuthentication will reject requests using JWT to authenticate,
|
||||
# even if those tokens are valid. Set this to True only if you need those
|
||||
# endpoints, and have configured settings 'JWT_AUTH' to override its default
|
||||
# values with secure values.
|
||||
FEATURES['ENABLE_JWT_AUTH'] = False
|
||||
|
||||
######################## CAS authentication ###########################
|
||||
|
||||
if FEATURES.get('AUTH_USE_CAS'):
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
"""
|
||||
Custom JWT decoding function for django_rest_framework jwt package.
|
||||
|
||||
Adds logging to facilitate debugging of InvalidTokenErrors. Also
|
||||
requires "exp" and "iat" claims to be present - the base package
|
||||
doesn't expose settings to enforce this.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
import jwt
|
||||
from rest_framework import exceptions
|
||||
from rest_framework_jwt.settings import api_settings
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def decode(token):
|
||||
"""
|
||||
Ensure InvalidTokenErrors are logged for diagnostic purposes, before
|
||||
failing authentication.
|
||||
"""
|
||||
if not settings.FEATURES.get('ENABLE_JWT_AUTH', False):
|
||||
msg = 'JWT auth not supported.'
|
||||
log.error(msg)
|
||||
raise exceptions.AuthenticationFailed(msg)
|
||||
|
||||
options = {
|
||||
'verify_exp': api_settings.JWT_VERIFY_EXPIRATION,
|
||||
'require_exp': True,
|
||||
'require_iat': True,
|
||||
}
|
||||
|
||||
try:
|
||||
return jwt.decode(
|
||||
token,
|
||||
api_settings.JWT_SECRET_KEY,
|
||||
api_settings.JWT_VERIFY,
|
||||
options=options,
|
||||
leeway=api_settings.JWT_LEEWAY,
|
||||
audience=api_settings.JWT_AUDIENCE,
|
||||
issuer=api_settings.JWT_ISSUER,
|
||||
algorithms=[api_settings.JWT_ALGORITHM]
|
||||
)
|
||||
except jwt.InvalidTokenError as exc:
|
||||
exc_type = u'{}.{}'.format(exc.__class__.__module__, exc.__class__.__name__)
|
||||
log.exception("raised_invalid_token: exc_type=%r, exc_detail=%r", exc_type, exc.message)
|
||||
raise
|
||||
@@ -4,40 +4,33 @@ Tests for OAuth2. This module is copied from django-rest-framework-oauth
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from collections import namedtuple
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import itertools
|
||||
import json
|
||||
from collections import namedtuple
|
||||
|
||||
import ddt
|
||||
from django.conf import settings
|
||||
from datetime import datetime, timedelta
|
||||
from django.conf.urls import patterns, url, include
|
||||
from django.contrib.auth.models import User
|
||||
from django.http import HttpResponse
|
||||
from django.test import TestCase
|
||||
from django.utils import unittest
|
||||
from django.utils.http import urlencode
|
||||
from mock import patch
|
||||
from nose.plugins.attrib import attr
|
||||
from oauth2_provider import models as dot_models
|
||||
from rest_framework import exceptions
|
||||
from provider import constants, scope
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework_oauth import permissions
|
||||
from rest_framework_oauth.compat import oauth2_provider, oauth2_provider_scope
|
||||
from rest_framework.test import APIRequestFactory, APIClient
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework_jwt.settings import api_settings
|
||||
from rest_framework_oauth import permissions
|
||||
from rest_framework_oauth.compat import oauth2_provider, oauth2_provider_scope
|
||||
|
||||
from lms.djangoapps.oauth_dispatch import adapters
|
||||
from openedx.core.lib.api import authentication
|
||||
from openedx.core.lib.api.tests.mixins import JwtMixin
|
||||
from provider import constants, scope
|
||||
from student.tests.factories import UserFactory
|
||||
|
||||
|
||||
factory = APIRequestFactory() # pylint: disable=invalid-name
|
||||
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER # pylint: disable=invalid-name
|
||||
|
||||
|
||||
class MockView(APIView): # pylint: disable=missing-docstring
|
||||
@@ -311,32 +304,3 @@ class OAuth2Tests(TestCase):
|
||||
self.assertEqual(response.status_code, scope_statuses.read_status)
|
||||
response = self.post_with_bearer_token('/oauth2-with-scope-test/', token=self.access_token.token)
|
||||
self.assertEqual(response.status_code, scope_statuses.write_status)
|
||||
|
||||
|
||||
@attr('shard_2')
|
||||
@ddt.ddt
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
class TestJWTAuthToggle(JwtMixin, TestCase):
|
||||
""" Test JWT authentication toggling with feature flag 'ENABLE_JWT_AUTH'."""
|
||||
|
||||
USERNAME = 'test-username'
|
||||
|
||||
def setUp(self):
|
||||
self.user = UserFactory.create(username=self.USERNAME)
|
||||
self.jwt_token = self.generate_id_token(user=self.user)
|
||||
super(TestJWTAuthToggle, self).setUp()
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_JWT_AUTH': True})
|
||||
def test_enabled_jwt_auth(self):
|
||||
""" Ensure that the JWT auth works fine when its feature flag
|
||||
'ENABLE_JWT_AUTH' is set.
|
||||
"""
|
||||
jwt_decode_handler(self.jwt_token)
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_JWT_AUTH': False})
|
||||
def test_disabled_jwt_auth(self):
|
||||
""" Ensure that the JWT auth raises exception when its feature flag
|
||||
'ENABLE_JWT_AUTH' is not set.
|
||||
"""
|
||||
with self.assertRaises(exceptions.AuthenticationFailed):
|
||||
jwt_decode_handler(self.jwt_token)
|
||||
|
||||
@@ -34,9 +34,10 @@ django-method-override==0.1.0
|
||||
#djangorestframework>=3.1,<3.2
|
||||
git+https://github.com/edx/django-rest-framework.git@3c72cb5ee5baebc4328947371195eae2077197b0#egg=djangorestframework==3.2.3
|
||||
django==1.8.12
|
||||
djangorestframework-jwt==1.7.2
|
||||
djangorestframework-jwt==1.8.0
|
||||
djangorestframework-oauth==1.1.0
|
||||
edx-ccx-keys==0.1.2
|
||||
edx-drf-extensions==0.5.0
|
||||
edx-lint==0.4.3
|
||||
edx-management-commands==0.1.1
|
||||
edx-django-oauth2-provider==1.0.3
|
||||
|
||||
Reference in New Issue
Block a user