Skip to content

Commit

Permalink
Ilee2u/acs endpoint (#369)
Browse files Browse the repository at this point in the history
* feat: support assessment control claims

* test: unit tests

* feat: ACS scope handling

* fix: correct acs url

* fix: removed drafted signal code

* test: added permissions test

* docs: added note on individual file testing

* docs: moved unit testing notes to readme

* chore: version bump

* temp: broken code to filter ACS scope perms

- Tried to create a filter in the access_token end point to only add the ACS scope only when proctoring is enabled
- This seems to hard to do without causing a circular dependency

* fix: removed filter for ACS access token

---------

Co-authored-by: Zach Hancock <[email protected]>
  • Loading branch information
ilee2u and zacharis278 authored May 5, 2023
1 parent c1f107f commit 61fb278
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 2 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ Please See the `releases tab <https://github.com/openedx/xblock-lti-consumer/rel
Unreleased
~~~~~~~~~~

9.3.0 - 2023-05-05
------------------
* Added handling for the ACS scope and ACS actions
* Added permissions class for ACS

9.2.1 - 2023-05-02
------------------
* Bug fix for adding platform name as an LTI parameter
Expand Down
7 changes: 7 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ See the `developer guide`_ for implementation details and other developer concer
Testing
*******

Unit Testing
============

* To run all of the unit tests at once, run `make test`
* To run tests on individual files in development, run `python ./test.py -k=[name of test file without .py]`
* For example, if you want to run the tests in test_permissions.py, run `python ./test.py -k=test_permissions`

Testing Against an LTI Provider
===============================

Expand Down
2 changes: 1 addition & 1 deletion lti_consumer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
from .apps import LTIConsumerApp
from .lti_xblock import LtiConsumerXBlock

__version__ = '9.2.1'
__version__ = '9.3.0'
3 changes: 3 additions & 0 deletions lti_consumer/lti_1p3/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@

# LTI-NRPS Scopes
'https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly',

# ACS Scope
'https://purl.imsglobal.org/spec/lti-ap/scope/control.all',
]


Expand Down
4 changes: 3 additions & 1 deletion lti_consumer/lti_1p3/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,6 @@ def access_token(self, token_request_data):
requested_scopes = token_request_data['scope'].split(' ')

for scope in requested_scopes:
# TODO: Add additional checks for permitted scopes
# Currently there are no scopes, because there is no use for
# these access tokens until a tool needs to access the LMS.
# LTI Advantage extensions make use of this.
Expand Down Expand Up @@ -873,6 +872,9 @@ def generate_launch_request(

self.set_extra_claim(proctoring_claims)

if self.proctoring_data.get("assessment_control_url"):
self.set_extra_claim(self.get_assessment_control_claim())

return super().generate_launch_request(preflight_response)

def check_and_decode_token(self, token):
Expand Down
21 changes: 21 additions & 0 deletions lti_consumer/lti_1p3/extensions/rest_framework/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,24 @@ def get_permission_scopes(self, request, view):
]

return scopes


class LtiProctoringAcsPermissions(LTIBasePermissions):
"""
LTI ACS Permissions.
This checks if the token included in the request
has the allowed scopes to perform ACS actions
(insert action examples here)
Link to relevant docs: (ims global docs url here)
"""

def get_permission_scopes(self, request, view):
"""
Return the LTI ACS scope.
There is only one: http://www.imsglobal.org/spec/proctoring/v1p0#h.ckrfa92a27mw
"""
return [
'https://purl.imsglobal.org/spec/lti-ap/scope/control.all',
]
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from lti_consumer.lti_1p3.extensions.rest_framework.permissions import (
LtiAgsPermissions,
LtiNrpsContextMembershipsPermissions,
LtiProctoringAcsPermissions,
)


Expand Down Expand Up @@ -276,3 +277,29 @@ def test_nrps_membership_permissions(self, token_scopes, is_allowed):
perm_class.has_permission(self.mock_request, mock_view),
is_allowed,
)

@ddt.data(
(["https://purl.imsglobal.org/spec/lti-ap/scope/control.all"], True),
([], False),
)
@ddt.unpack
def test_proctoring_acs_permissions(self, token_scopes, is_allowed):
"""
Test if LTI Proctoring ACS Permissions endpoint is availabe for correct token.
"""
perm_class = LtiProctoringAcsPermissions()

mock_view = MagicMock()

# Make token and include it in the mock request
token = self._make_token(token_scopes)
self.mock_request.headers = {
"Authorization": "Bearer {}".format(token)
}

# Test scores view
mock_view.action = 'list'
self.assertEqual(
perm_class.has_permission(self.mock_request, mock_view),
is_allowed,
)

0 comments on commit 61fb278

Please sign in to comment.