-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #38 from uw-it-aca/feature/django-views
adds authz for rest view
- Loading branch information
Showing
11 changed files
with
210 additions
and
196 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
from django.conf import settings | ||
from django.test import TestCase | ||
from django.core.exceptions import ImproperlyConfigured | ||
from blti.validators import BLTIOauth, BLTIRoles | ||
from blti.crypto import aes128cbc | ||
from blti.models import BLTIData | ||
from blti import BLTI, BLTIException | ||
|
||
|
||
|
@@ -21,6 +23,43 @@ def test_get_consumer(self): | |
self.assertEquals(BLTIOauth().get_consumer('ABC').secret, '12345') | ||
|
||
|
||
class BLTIDataTest(TestCase): | ||
def test_attributes(self): | ||
params = getattr(settings, 'CANVAS_LTI_V1_LAUNCH_PARAMS', {}) | ||
blti = BLTIData(**params) | ||
|
||
self.assertEquals(blti.link_title, 'Example App') | ||
self.assertEquals(blti.return_url, | ||
'https://example.instructure.com/courses/123456') | ||
self.assertEquals(blti.canvas_course_id, '123456') | ||
self.assertEquals(blti.course_sis_id, '2018-spring-ABC-101-A') | ||
self.assertEquals(blti.course_short_name, 'ABC 101 A') | ||
self.assertEquals(blti.course_long_name, 'ABC 101 A: Example Course') | ||
self.assertEquals(blti.canvas_user_id, '123456') | ||
self.assertEquals(blti.user_login_id, 'javerage') | ||
self.assertEquals(blti.user_sis_id, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') | ||
self.assertEquals(blti.user_full_name, 'James Average') | ||
self.assertEquals(blti.user_first_name, 'James') | ||
self.assertEquals(blti.user_last_name, 'Average') | ||
self.assertEquals(blti.user_email, '[email protected]') | ||
self.assertEquals( | ||
blti.user_avatar_url, ( | ||
'https://example.instructure.com/images/thumbnails/123456/' | ||
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')) | ||
self.assertEquals(blti.canvas_account_id, '12345') | ||
self.assertEquals(blti.account_sis_id, 'example:account') | ||
self.assertEquals(blti.canvas_api_domain, 'example.instructure.com') | ||
|
||
def test_get(self): | ||
params = getattr(settings, 'CANVAS_LTI_V1_LAUNCH_PARAMS', {}) | ||
blti = BLTIData(**params) | ||
|
||
self.assertEquals(blti.get('custom_canvas_course_id'), '123456') | ||
self.assertEquals(blti.get('lis_person_contact_email_primary'), | ||
'[email protected]') | ||
self.assertEquals(blti.get('invalid_param_name'), None) | ||
|
||
|
||
class BLTIRolesTest(TestCase): | ||
def test_has_admin_role(self): | ||
self.assertEquals( | ||
|
@@ -40,6 +79,10 @@ def test_has_learner_role(self): | |
False, BLTIRoles().has_learner_role(['Faculty', 'Staff'])) | ||
|
||
def test_validate(self): | ||
blti = None | ||
self.assertRaises( | ||
BLTIException, BLTIRoles().validate, blti, 'member') | ||
|
||
blti = {'roles': 'Member'} | ||
self.assertEquals(None, BLTIRoles().validate(blti, 'member')) | ||
self.assertRaises( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
from django.http import HttpResponse | ||
from django.views.generic.base import TemplateView | ||
from django.views.decorators.csrf import csrf_exempt | ||
from blti import BLTI, BLTIException | ||
from blti.models import BLTIData | ||
from blti.validators import BLTIOauth, BLTIRoles | ||
from blti.performance import log_response_time | ||
import json | ||
try: | ||
from urllib import unquote_plus | ||
except ImportError: | ||
from urllib.parse import unquote_plus # Python3 | ||
|
||
|
||
class BLTIView(TemplateView): | ||
authorized_role = 'member' | ||
|
||
def dispatch(self, request, *args, **kwargs): | ||
try: | ||
kwargs['blti_params'] = self.validate(request) | ||
except BLTIException as err: | ||
self.template_name = 'blti/401.html' | ||
return self.render_to_response({'error': err}, status=401) | ||
|
||
return super(BLTIView, self).dispatch(request, *args, **kwargs) | ||
|
||
def render_to_response(self, context, **kwargs): | ||
response = super(BLTIView, self).render_to_response(context, **kwargs) | ||
self.add_headers(response=response, **kwargs) | ||
return response | ||
|
||
def add_headers(self, **kwargs): | ||
pass | ||
|
||
def get_session(self, request): | ||
return BLTI().get_session(request) | ||
|
||
def set_session(self, request, **kwargs): | ||
BLTI().set_session(request, **kwargs) | ||
|
||
def validate(self, request): | ||
blti_params = self.get_session(request) | ||
self.authorize(blti_params) | ||
return blti_params | ||
|
||
def authorize(self, blti_params): | ||
BLTIRoles().validate(blti_params, visibility=self.authorized_role) | ||
self.blti = BLTIData(blti_params) | ||
|
||
|
||
class BLTILaunchView(BLTIView): | ||
http_method_names = ['post'] | ||
|
||
@csrf_exempt | ||
def dispatch(self, request, *args, **kwargs): | ||
return super(BLTILaunchView, self).dispatch(request, *args, **kwargs) | ||
|
||
def validate(self, request): | ||
params = {} | ||
body = request.read() | ||
try: | ||
params = dict((k, v) for k, v in [tuple( | ||
map(unquote_plus, kv.split('=')) | ||
) for kv in body.split('&')]) | ||
except Exception: | ||
raise BLTIException('Missing or malformed parameter or value') | ||
|
||
blti_params = BLTIOauth().validate(request, params=params) | ||
self.authorize(blti_params) | ||
self.set_session(request, **blti_params) | ||
|
||
return blti_params | ||
|
||
|
||
class RawBLTIView(BLTILaunchView): | ||
template_name = 'blti/raw.html' | ||
authorized_role = 'admin' | ||
|
||
|
||
class RESTDispatch(BLTIView): | ||
""" | ||
A superclass for API views | ||
""" | ||
authorized_role = 'member' | ||
|
||
@log_response_time | ||
def dispatch(self, request, *args, **kwargs): | ||
try: | ||
kwargs['blti_params'] = self.validate(request) | ||
except BLTIException as ex: | ||
return self.error_response(401, ex) | ||
|
||
return super(BLTIView, self).dispatch(request, *args, **kwargs) | ||
|
||
def render_to_response(self, context, **kwargs): | ||
return self.json_response(content=context) | ||
|
||
def error_response(self, status, message='', content={}): | ||
content['error'] = str(message) | ||
return self.json_response(content=content, status=status) | ||
|
||
def json_response(self, content={}, status=200): | ||
response = HttpResponse(json.dumps(content), | ||
status=status, | ||
content_type='application/json') | ||
self.add_headers(response=response, **kwargs) | ||
return response |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.