Skip to content

Commit 61fb278

Browse files
ilee2uzacharis278
andauthored
Ilee2u/acs endpoint (#369)
* 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 <zhancock@edx.org>
1 parent c1f107f commit 61fb278

7 files changed

Lines changed: 67 additions & 2 deletions

File tree

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ Please See the `releases tab <https://github.com/openedx/xblock-lti-consumer/rel
1616
Unreleased
1717
~~~~~~~~~~
1818

19+
9.3.0 - 2023-05-05
20+
------------------
21+
* Added handling for the ACS scope and ACS actions
22+
* Added permissions class for ACS
23+
1924
9.2.1 - 2023-05-02
2025
------------------
2126
* Bug fix for adding platform name as an LTI parameter

README.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ See the `developer guide`_ for implementation details and other developer concer
145145
Testing
146146
*******
147147

148+
Unit Testing
149+
============
150+
151+
* To run all of the unit tests at once, run `make test`
152+
* To run tests on individual files in development, run `python ./test.py -k=[name of test file without .py]`
153+
* For example, if you want to run the tests in test_permissions.py, run `python ./test.py -k=test_permissions`
154+
148155
Testing Against an LTI Provider
149156
===============================
150157

lti_consumer/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
from .apps import LTIConsumerApp
55
from .lti_xblock import LtiConsumerXBlock
66

7-
__version__ = '9.2.1'
7+
__version__ = '9.3.0'

lti_consumer/lti_1p3/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565

6666
# LTI-NRPS Scopes
6767
'https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly',
68+
69+
# ACS Scope
70+
'https://purl.imsglobal.org/spec/lti-ap/scope/control.all',
6871
]
6972

7073

lti_consumer/lti_1p3/consumer.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,6 @@ def access_token(self, token_request_data):
456456
requested_scopes = token_request_data['scope'].split(' ')
457457

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

874873
self.set_extra_claim(proctoring_claims)
875874

875+
if self.proctoring_data.get("assessment_control_url"):
876+
self.set_extra_claim(self.get_assessment_control_claim())
877+
876878
return super().generate_launch_request(preflight_response)
877879

878880
def check_and_decode_token(self, token):

lti_consumer/lti_1p3/extensions/rest_framework/permissions.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,24 @@ def get_permission_scopes(self, request, view):
9999
]
100100

101101
return scopes
102+
103+
104+
class LtiProctoringAcsPermissions(LTIBasePermissions):
105+
"""
106+
LTI ACS Permissions.
107+
108+
This checks if the token included in the request
109+
has the allowed scopes to perform ACS actions
110+
(insert action examples here)
111+
112+
Link to relevant docs: (ims global docs url here)
113+
"""
114+
115+
def get_permission_scopes(self, request, view):
116+
"""
117+
Return the LTI ACS scope.
118+
There is only one: http://www.imsglobal.org/spec/proctoring/v1p0#h.ckrfa92a27mw
119+
"""
120+
return [
121+
'https://purl.imsglobal.org/spec/lti-ap/scope/control.all',
122+
]

lti_consumer/lti_1p3/tests/extensions/rest_framework/test_permissions.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from lti_consumer.lti_1p3.extensions.rest_framework.permissions import (
1414
LtiAgsPermissions,
1515
LtiNrpsContextMembershipsPermissions,
16+
LtiProctoringAcsPermissions,
1617
)
1718

1819

@@ -276,3 +277,29 @@ def test_nrps_membership_permissions(self, token_scopes, is_allowed):
276277
perm_class.has_permission(self.mock_request, mock_view),
277278
is_allowed,
278279
)
280+
281+
@ddt.data(
282+
(["https://purl.imsglobal.org/spec/lti-ap/scope/control.all"], True),
283+
([], False),
284+
)
285+
@ddt.unpack
286+
def test_proctoring_acs_permissions(self, token_scopes, is_allowed):
287+
"""
288+
Test if LTI Proctoring ACS Permissions endpoint is availabe for correct token.
289+
"""
290+
perm_class = LtiProctoringAcsPermissions()
291+
292+
mock_view = MagicMock()
293+
294+
# Make token and include it in the mock request
295+
token = self._make_token(token_scopes)
296+
self.mock_request.headers = {
297+
"Authorization": "Bearer {}".format(token)
298+
}
299+
300+
# Test scores view
301+
mock_view.action = 'list'
302+
self.assertEqual(
303+
perm_class.has_permission(self.mock_request, mock_view),
304+
is_allowed,
305+
)

0 commit comments

Comments
 (0)