Commit 5a7bc019 by Clinton Blackburn Committed by Clinton Blackburn

JWT authentication updates

- Using jwt_decode_handler from edx-drf-extensions
- Updated djangorestframework-jwt
- Removed feature flag around JWT auth

ECOM-4221
parent b6d5c614
......@@ -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'):
......
"""
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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment