Merge pull request #12954 from edx/renzo/extract-token-generation
Unify JWT generation code
This commit is contained in:
@@ -18,12 +18,13 @@ from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from provider.oauth2.models import Client
|
||||
|
||||
from edxnotes.exceptions import EdxNotesParseError, EdxNotesServiceUnavailable
|
||||
from edxnotes.plugins import EdxNotesTab
|
||||
from courseware.views.views import get_current_child
|
||||
from courseware.access import has_access
|
||||
from openedx.core.lib.token_utils import get_id_token
|
||||
from openedx.core.lib.token_utils import JwtBuilder
|
||||
from student.models import anonymous_id_for_user
|
||||
from util.date_utils import get_default_time_display
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -52,7 +53,19 @@ def get_edxnotes_id_token(user):
|
||||
"""
|
||||
Returns generated ID Token for edxnotes.
|
||||
"""
|
||||
return get_id_token(user, CLIENT_NAME)
|
||||
# TODO: Use the system's JWT_AUDIENCE and JWT_SECRET_KEY instead of client ID and name.
|
||||
try:
|
||||
client = Client.objects.get(name=CLIENT_NAME)
|
||||
except Client.DoesNotExist:
|
||||
raise ImproperlyConfigured(
|
||||
'OAuth2 Client with name [{}] does not exist.'.format(CLIENT_NAME)
|
||||
)
|
||||
|
||||
scopes = ['email', 'profile']
|
||||
expires_in = settings.OAUTH_ID_TOKEN_EXPIRATION
|
||||
jwt = JwtBuilder(user, secret=client.client_secret).build_token(scopes, expires_in, aud=client.client_id)
|
||||
|
||||
return jwt
|
||||
|
||||
|
||||
def get_token_url(course_id):
|
||||
|
||||
@@ -4,6 +4,8 @@ OAuth Dispatch test mixins
|
||||
import jwt
|
||||
from django.conf import settings
|
||||
|
||||
from student.models import UserProfile, anonymous_id_for_user
|
||||
|
||||
|
||||
class AccessTokenMixin(object):
|
||||
""" Mixin for tests dealing with OAuth 2 access tokens. """
|
||||
@@ -35,11 +37,21 @@ class AccessTokenMixin(object):
|
||||
'iss': issuer,
|
||||
'preferred_username': user.username,
|
||||
'scopes': scopes,
|
||||
'sub': anonymous_id_for_user(user, None),
|
||||
}
|
||||
|
||||
if 'email' in scopes:
|
||||
expected['email'] = user.email
|
||||
|
||||
if 'profile' in scopes:
|
||||
try:
|
||||
name = UserProfile.objects.get(user=user).name
|
||||
except UserProfile.DoesNotExist:
|
||||
name = None
|
||||
|
||||
expected['name'] = name
|
||||
expected['administrator'] = user.is_staff
|
||||
|
||||
self.assertDictContainsSubset(expected, payload)
|
||||
|
||||
return payload
|
||||
|
||||
@@ -17,6 +17,7 @@ from edx_oauth2_provider import views as dop_views # django-oauth2-provider vie
|
||||
from oauth2_provider import models as dot_models, views as dot_views # django-oauth-toolkit
|
||||
|
||||
from openedx.core.djangoapps.theming import helpers
|
||||
from openedx.core.lib.token_utils import JwtBuilder
|
||||
|
||||
from . import adapters
|
||||
|
||||
@@ -87,15 +88,6 @@ class AccessTokenView(_DispatchingView):
|
||||
dot_view = dot_views.TokenView
|
||||
dop_view = dop_views.AccessTokenView
|
||||
|
||||
@cached_property
|
||||
def claim_handlers(self):
|
||||
""" Returns a dictionary mapping scopes to methods that will add claims to the JWT payload. """
|
||||
|
||||
return {
|
||||
'email': self._attach_email_claim,
|
||||
'profile': self._attach_profile_claim
|
||||
}
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
response = super(AccessTokenView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
@@ -103,7 +95,7 @@ class AccessTokenView(_DispatchingView):
|
||||
expires_in, scopes, user = self._decompose_access_token_response(request, response)
|
||||
|
||||
content = {
|
||||
'access_token': self._generate_jwt(user, scopes, expires_in),
|
||||
'access_token': JwtBuilder(user).build_token(scopes, expires_in),
|
||||
'expires_in': expires_in,
|
||||
'token_type': 'JWT',
|
||||
'scope': ' '.join(scopes),
|
||||
@@ -123,43 +115,6 @@ class AccessTokenView(_DispatchingView):
|
||||
expires_in = content['expires_in']
|
||||
return expires_in, scopes, user
|
||||
|
||||
def _generate_jwt(self, user, scopes, expires_in):
|
||||
""" Returns a JWT access token. """
|
||||
now = int(time())
|
||||
jwt_auth = helpers.get_value("JWT_AUTH", settings.JWT_AUTH)
|
||||
payload = {
|
||||
'iss': jwt_auth['JWT_ISSUER'],
|
||||
'aud': jwt_auth['JWT_AUDIENCE'],
|
||||
'exp': now + expires_in,
|
||||
'iat': now,
|
||||
'preferred_username': user.username,
|
||||
'scopes': scopes,
|
||||
}
|
||||
|
||||
for scope in scopes:
|
||||
handler = self.claim_handlers.get(scope)
|
||||
|
||||
if handler:
|
||||
handler(payload, user)
|
||||
|
||||
secret = jwt_auth['JWT_SECRET_KEY']
|
||||
token = jwt.encode(payload, secret, algorithm=jwt_auth['JWT_ALGORITHM'])
|
||||
|
||||
return token
|
||||
|
||||
def _attach_email_claim(self, payload, user):
|
||||
""" Add the email claim details to the JWT payload. """
|
||||
payload['email'] = user.email
|
||||
|
||||
def _attach_profile_claim(self, payload, user):
|
||||
""" Add the profile claim details to the JWT payload. """
|
||||
payload.update({
|
||||
'family_name': user.last_name,
|
||||
'name': user.get_full_name(),
|
||||
'given_name': user.first_name,
|
||||
'administrator': user.is_staff,
|
||||
})
|
||||
|
||||
|
||||
class AuthorizationView(_DispatchingView):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user