def lti_launch(self, lti_consumer, lti_resource_link_id, assignment_uuid=None, query_assignment_uuid=None, custom_puid=None, nonce=None, timestamp=None, follow_redirects=True, **kwargs): launch_url = "http://localhost/api/lti/auth" launch_params = kwargs.copy() launch_params['resource_link_id'] = lti_resource_link_id if assignment_uuid: launch_params['custom_assignment'] = assignment_uuid if custom_puid: launch_params['custom_puid'] = custom_puid if query_assignment_uuid: launch_url = launch_url + "?assignment=" + query_assignment_uuid tool_consumer = ToolConsumer(lti_consumer.oauth_consumer_key, lti_consumer.oauth_consumer_secret, params=launch_params, launch_url=launch_url) launch_request = tool_consumer.generate_launch_request( nonce=nonce, timestamp=timestamp) launch_data = parse_qs(launch_request.body.decode('utf-8')) rv = self.client.post('/api/lti/auth', data=launch_data, follow_redirects=follow_redirects) yield rv rv.close()
def test_launch_request_with_qs(self): """ test that qs params in launch url are ok """ launch_params = { 'lti_version': 'abc', 'lti_message_type': 'def', 'resource_link_id': '123' } tc = ToolConsumer('client_key', 'client_secret', launch_url='http://example.edu/foo?bar=1', params=launch_params) launch_req = tc.generate_launch_request(nonce='wxyz7890', timestamp='2345678901') got = parse_qs(unquote(launch_req.body)) correct = launch_params.copy() correct.update({ 'oauth_nonce': 'wxyz7890', 'oauth_timestamp': '2345678901', 'oauth_version': '1.0', 'oauth_signature_method': 'HMAC-SHA1', 'oauth_consumer_key': 'client_key', 'oauth_signature': 'UH2l86Wq/g5Mu64GpCRcec6tEYY=', }) self.assertEqual(got, correct)
def test_lti_validation_from_ltidict_ok(): target_path = reverse("hx_lti_initializer:launch_lti") launch_url = "http://testserver{}".format(target_path) resource_link_id = "some_string_to_be_the_fake_resource_link_id" consumer = ToolConsumer( consumer_key=settings.CONSUMER_KEY, consumer_secret=settings.TEST_COURSE_LTI_SECRET, launch_url=launch_url, params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": resource_link_id, "lis_person_sourcedid": "instructor_1", "lis_outcome_service_url": "fake_url", "user_id": "instructor_1-anon", "roles": ["Instructor", "Administrator"], "context_id": settings.TEST_COURSE, }, ) params = consumer.generate_launch_data() for key in params: print("****** LTI[{}]: {}".format(key, params[key])) factory = RequestFactory() request = factory.post(target_path, data=params) validator = LTIRequestValidator() tool_provider = DjangoToolProvider.from_django_request(request=request) request_is_valid = tool_provider.is_valid_request(validator) assert request_is_valid
def test_launchLti_from_LTIdict_ok( lti_path, lti_launch_url, course_instructor_factory, ): course, user = course_instructor_factory() course.course_id = settings.TEST_COURSE # force context_id resource_link_id = "FakeResourceLinkID" consumer = ToolConsumer( consumer_key=settings.CONSUMER_KEY, consumer_secret=settings.TEST_COURSE_LTI_SECRET, launch_url=lti_launch_url, params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": resource_link_id, "lis_person_sourcedid": user.name, "lis_outcome_service_url": "fake_url", "user_id": user.anon_id, "roles": ["Instructor"], "context_id": course.course_id, }, ) params = consumer.generate_launch_data() client = Client(enforce_csrf_checks=False) response = client.post( lti_path, data=params, ) assert response.status_code == 302 expected_url = (reverse("hx_lti_initializer:course_admin_hub") + f"?resource_link_id={resource_link_id}" + f"&utm_source={client.session.session_key}") assert response.url == expected_url
def test_generate_launch_request(self): launch_params = { 'lti_version': 'foo', 'lti_message_type': 'bar', 'resource_link_id': 'baz' } tc = ToolConsumer('client_key', 'client_secret', launch_url='http://example.edu/', params=launch_params) launch_req = tc.generate_launch_request(nonce='abcd1234', timestamp='1234567890') self.assertIsInstance(launch_req, PreparedRequest) got = parse_qs(unquote(launch_req.body)) correct = launch_params.copy() correct.update({ 'oauth_nonce': 'abcd1234', 'oauth_timestamp': '1234567890', 'oauth_version': '1.0', 'oauth_signature_method': 'HMAC-SHA1', 'oauth_consumer_key': 'client_key', 'oauth_signature': 'u2xlj 1gF4y 6gKHNeiL9cN3tOI=', }) self.assertEqual(got, correct)
def test_lti_validation_default_key_unknown_consumer_fail(): target_path = "/some_path" launch_url = "http://testserver{}".format(target_path) resource_link_id = "some_string_to_be_the_fake_resource_link_id" consumer = ToolConsumer( consumer_key="unknown_consumer_key", consumer_secret=settings.LTI_SECRET, launch_url=launch_url, params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": resource_link_id, "lis_person_sourcedid": "instructor_1", "lis_outcome_service_url": "fake_url", "user_id": "instructor_1-anon", "roles": ["Instructor", "Administrator"], "context_id": "fake_course", }, ) params = consumer.generate_launch_data() for key in params: print("****** LTI[{}]: {}".format(key, params[key])) factory = RequestFactory() request = factory.post(target_path, data=params) validator = LTIRequestValidator() tool_provider = DjangoToolProvider.from_django_request(request=request) request_is_valid = tool_provider.is_valid_request(validator) assert not request_is_valid
def show_testcase(request, testcase_id): ''' shows a testcase with all parameters. Keyword arguments: request -- the calling HttpRequest testcase_id -- id of the testcase to show ''' testcase = get_object_or_404(Testcase, id=testcase_id) lps = {} for lp in testcase.launchparam_set.all(): lps[lp.name] = lp.value params = {'testcase': testcase} try: consumer = ToolConsumer(consumer_key=testcase.consumer_key, consumer_secret=testcase.consumer_secret, launch_url=testcase.launch_url, params=lps) params['launch_data'] = consumer.generate_launch_data() params['launch_url'] = consumer.launch_url except Exception as inst: params['error_name'] = str(type(inst).__name__) params['error_detail'] = str(inst) return render(request, 'consumer/show_testcase.html', params)
def test_can_login(self, testapp, app, db): app.config['SERVER_NAME'] = 'localhost' #app.config['SERVER_PORT'] = 5000 app.config['PREFERRED_URL_SCHEME'] = 'http' consumer = ConsumerFactory() consumer.save() params = { 'lti_message_type': 'basic-lti-launch-request', 'lti_version': 'LTI-1p0', 'resource_link_id': 'same.site.org-9fcae62972a240e488ca1de83dc4a6d9', } tool_consumer = ToolConsumer(consumer_key=consumer.client_key, consumer_secret=consumer.secret_key, launch_url=url_for( 'lti_launch.lti_launch', _external=True), params=params) lti_params = tool_consumer.generate_launch_data() #res = testapp.post(url_for('lti_launch.lti_launch', _external=True), lti_params) res = testapp.post(url_for('lti_launch.lti_launch', _external=True), lti_params) assert res.status_code == 200
def get_lti_url(course, user_id, task_id): config = syllabus.get_config() inginious_config = config['courses'][course]['inginious'] consumer = ToolConsumer( consumer_key=inginious_config['lti']['consumer_key'], consumer_secret=inginious_config['lti']['consumer_secret'], launch_url='%s/lti/%s/%s' % (inginious_config['url'], inginious_config['course_id'], task_id), params={ 'lti_message_type': 'basic-lti-launch-request', 'lti_version': "1.1", 'resource_link_id': "syllabus_{}_{}".format(course, task_id), 'user_id': user_id, }) d = consumer.generate_launch_data() data = parse.urlencode(d).encode() req = urllib_request.Request( '%s/lti/%s/%s' % (inginious_config['url'], inginious_config['course_id'], task_id), data=data) resp = urllib_request.urlopen(req) task_url = resp.geturl() lti_url_regex = re.compile("%s/@[0-9a-fA-F]+@/lti/task/?" % inginious_config['url']) if not lti_url_regex.match(task_url): pass #raise Exception("INGInious returned the wrong url: %s vs %s" % (task_url, str(lti_url_regex))) return task_url
def test_constructor(self): client_id = generate_client_id() client_secret = generate_token() tc = ToolConsumer(client_id, client_secret, launch_url='http://example.edu') self.assertIsInstance(tc.launch_params, LaunchParams) lp = LaunchParams() tc = ToolConsumer(client_id, client_secret, launch_url='http://example.edu', params=lp) self.assertEqual(tc.launch_params, lp) lp_dict = {'resource_link_id': 1} tc = ToolConsumer(client_id, client_secret, launch_url='http://example.edu', params=lp_dict) self.assertIsInstance(tc.launch_params, LaunchParams) self.assertEqual(tc.launch_params._params.get('resource_link_id'), 1) # no launch_url should raise exception self.failUnlessRaises(InvalidLTIConfigError, ToolConsumer, client_id, client_secret, params=lp_dict) # but confirm that 'launch_url' can still be passed in params # (backwards compatibility) lp_dict['launch_url'] = 'http://example.edu' tc = ToolConsumer(client_id, client_secret, params=lp_dict) self.assertEqual(tc.launch_url, 'http://example.edu')
def test_launchLti(random_course_instructor): instructor = random_course_instructor["profile"] course = random_course_instructor["course"] target_path = "/lti_init/launch_lti/" launch_url = "http://testserver{}".format(target_path) consumer = ToolConsumer( consumer_key=settings.CONSUMER_KEY, consumer_secret=settings.LTI_SECRET, launch_url=launch_url, params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": "FakeResourceLinkID", "lis_person_sourcedid": instructor.name, "lis_outcome_service_url": "fake_url", "user_id": instructor.anon_id, "roles": ["Instructor"], "context_id": course.course_id, }, ) params = consumer.generate_launch_data() # req = consumer.generate_launch_request() client = Client(enforce_csrf_checks=False) response = client.post( target_path, data=params, ) assert response.status_code == 403 assert response.content == "hey"
def test_launchLti_from_LTIdict_wrong_secret( lti_path, lti_launch_url, course_instructor_factory, ): course, user = course_instructor_factory() consumer = ToolConsumer( consumer_key=settings.CONSUMER_KEY, consumer_secret=settings.TEST_COURSE_LTI_SECRET, launch_url=lti_launch_url, params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": "FakeResourceLinkID", "lis_person_sourcedid": user.name, "lis_outcome_service_url": "fake_url", "user_id": user.anon_id, "roles": ["Instructor"], "context_id": course.course_id, }, ) params = consumer.generate_launch_data() client = Client(enforce_csrf_checks=False) response = client.post( lti_path, data=params, ) assert response.status_code == 403
def test_wsauth_ok(): ### # prep to create lti session instructor_name = "sylvia_plath" instructor_edxid = "{}{}".format(randint(1000, 65534), randint(1000, 65534)) course_id = "hx+FancierCourse+TermCode+Year" clean_course_id = re.sub(r"[\W_]", "-", course_id) target_path = reverse("hx_lti_initializer:launch_lti") launch_url = "http://testserver{}".format(target_path) resource_link_id = "some_string_to_be_THE_fake_resource_link_id" consumer = ToolConsumer( consumer_key=settings.CONSUMER_KEY, consumer_secret=settings.LTI_SECRET, launch_url=launch_url, params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": resource_link_id, "lis_person_sourcedid": instructor_name, "lis_outcome_service_url": "fake_url", "user_id": instructor_edxid, "roles": ["Instructor", "Administrator"], "context_id": course_id, "context_title": "{}+title".format(course_id), }, ) params = consumer.generate_launch_data() client = Client(enforce_csrf_checks=False) response = client.post( target_path, data=params, ) utm_source = response.cookies.get("sessionid").value # prep to create lti session ### application = URLRouter([ re_path(r"^ws/notification/(?P<room_name>[^/]+)/$", NotificationConsumer), ]) mut = SessionAuthMiddleware(application) mock_scope = { "type": "websocket", "path": "/ws/notification/{}--ad10b1d2--1/".format(clean_course_id), "query_string": "utm_source={}&resource_link_id={}".format( utm_source, resource_link_id).encode("utf-8"), "headers": [], "subprotocols": [], } inner_consumer = mut.__call__(scope=mock_scope) assert "hxat_auth" in mock_scope assert mock_scope["hxat_auth"] == "authenticated"
async def test_wsconn_ok(): ### # prep to create lti session instructor_name = "sylvia_plath" instructor_edxid = "{}{}".format(randint(1000, 65534), randint(1000, 65534)) course_id = "hx+FancierCourse+TermCode+Year" clean_course_id = re.sub(r"[\W_]", "-", course_id) target_path = reverse("hx_lti_initializer:launch_lti") launch_url = "http://testserver{}".format(target_path) resource_link_id = "some_string_to_be_THE_fake_resource_link_id" consumer = ToolConsumer( consumer_key=settings.CONSUMER_KEY, consumer_secret=settings.LTI_SECRET, launch_url=launch_url, params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": resource_link_id, "lis_person_sourcedid": instructor_name, "lis_outcome_service_url": "fake_url", "user_id": instructor_edxid, "roles": ["Instructor", "Administrator"], "context_id": course_id, "context_title": "{}+title".format(course_id), }, ) params = consumer.generate_launch_data() client = Client(enforce_csrf_checks=False) response = client.post( target_path, data=params, ) utm_source = response.cookies.get("sessionid").value # prep to create lti session ### application = SessionAuthMiddleware( URLRouter([ re_path(r"^ws/notification/(?P<room_name>[^/]+)/$", NotificationConsumer), ])) path = "/ws/notification/{}--dvorak--1/?utm_source={}&resource_link_id={}".format( clean_course_id, utm_source, resource_link_id) communicator = WebsocketCommunicator(application, path) connected, subprotocol = await communicator.connect() assert connected # not sure receive_nothing() is needed # it might be good to have some resp from server at application level await communicator.receive_nothing() await communicator.disconnect()
def test_has_required_params(self): client_id = generate_client_id() client_secret = generate_token() tc = ToolConsumer(client_id, client_secret, launch_url='http://example.edu') self.assertFalse(tc.has_required_params()) tc.launch_params['resource_link_id'] = generate_token() self.assertTrue(tc.has_required_params())
def hxat_lti_launch(locust): target_path = "/lti_init/launch_lti/" consumer = ToolConsumer( consumer_key=locust.hxat_client.consumer_key, consumer_secret=locust.hxat_client.secret_key, launch_url="{}{}".format(locust.host, target_path), params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": locust.hxat_client.resource_link_id, "lis_person_sourcedid": locust.hxat_client.user_name, # lis_outcome_service_url sets graded assignment # "lis_outcome_service_url": os.environ.get('LIS_OUTCOME_SERVICE_URL', 'fake_url'), "user_id": locust.hxat_client.user_id, "roles": locust.hxat_client.user_roles, "context_id": locust.hxat_client.context_id, "context_title": locust.hxat_client.context_title, "custom_collection_id": locust.hxat_client.collection_id, "custom_object_id": locust.hxat_client.target_source_id, }, ) headers = { "Content-Type": "application/x-www-form-urlencoded", } params = consumer.generate_launch_data() response = locust.client.post( target_path, catch_response=True, name="/lti_launch/", headers=headers, data=params, verify=locust.ssl_verify, ) if response.status_code == requests.codes.ok: if response.content == "": response.failure("no data") return False else: # locust.log('*..*..*..*..*..*..*..*..*..*..*..*..*..*..*..*..*..*..*..*..*') # locust.log(response.content) cookie_sid = response.cookies.get("sessionid", None) if not cookie_sid: response.failure("missing session-id cookies") return False else: locust.hxat_client.utm_source = cookie_sid response.success() return True else: response.failure("status code: {}".format(response.status_code)) return False
def lti_launch(self, lti_consumer, lti_resource_link_id, assignment_uuid=None, query_assignment_uuid=None, nonce=None, timestamp=None, follow_redirects=True, invalid_launch=False, **kwargs): launch_url = "http://localhost/api/lti/auth" oauth_signature = kwargs.pop('oauth_signature', None) launch_params = kwargs.copy() launch_params['resource_link_id'] = lti_resource_link_id if assignment_uuid: launch_params['custom_assignment'] = assignment_uuid if query_assignment_uuid: launch_url = launch_url+"?assignment="+query_assignment_uuid # add basic required launch parameters if not 'lti_version' in launch_params: launch_params['lti_version'] = "LTI-1p0" if not 'lti_message_type' in launch_params: launch_params['lti_message_type'] = "basic-lti-launch-request" if 'roles' in launch_params and launch_params.get('roles') == None: launch_params.pop('roles') tool_consumer = ToolConsumer( lti_consumer.oauth_consumer_key, lti_consumer.oauth_consumer_secret, params=launch_params, launch_url=launch_url ) # overwrite lti_version and lti_message_type if needed (set by lti.LaunchParams) if 'lti_version' in launch_params and launch_params.get('lti_version') == None: tool_consumer.launch_params._params.pop('lti_version') if 'lti_message_type' in launch_params and launch_params.get('lti_message_type') == None: tool_consumer.launch_params._params.pop('lti_message_type') if invalid_launch: with mock.patch.object(ToolConsumer, 'has_required_params', return_value=True): launch_request = tool_consumer.generate_launch_request(nonce=nonce, timestamp=timestamp) else: launch_request = tool_consumer.generate_launch_request(nonce=nonce, timestamp=timestamp) launch_data = parse_qs(launch_request.body.decode('utf-8')) # overwrite oauth_signature for tests if invalid_launch and oauth_signature: launch_data['oauth_signature'] = oauth_signature rv = self.client.post('/api/lti/auth', data=launch_data, follow_redirects=follow_redirects) yield rv rv.close()
def test_generate_launch_data_with_empty_value(self): launch_params = { 'lti_version': 'abc', 'lti_message_type': 'def', 'resource_link_id': '123', 'custom_test_value': '', } tc = ToolConsumer('client_key', 'client_secret', launch_url='http://example.edu/', params=launch_params) got = tc.generate_launch_data(nonce='wxyz7890', timestamp='2345678901') self.assertEqual(got['custom_test_value'], '')
def test_lti_launch_correct_query(self, role, mock_learner_flow): """ Test for checking LTI query. :param role: String identifier for role in platform :param mock_learner_flow: mocking method of bridge_lti.provider.learner_flow :param mock_instructor_flow: mocking method of bridge_lti.provider.instructor_flow """ mock_learner_flow.return_value = HttpResponse(status=200) consumer_prams = { 'consumer_key': self.lti_provider.consumer_key, 'consumer_secret': self.lti_provider.consumer_secret, 'launch_url': f"http://{settings.BRIDGE_HOST}" + reverse('lti:launch', kwargs={ 'collection_slug': self.collection1.slug, 'group_slug': str(self.test_cg.slug) }), 'params': { # Required parameters 'lti_message_type': 'basic-lti-launch-request', 'lti_version': 'LTI-1p0', # The random value is used for the test purpose 'resource_link_id': '-523523423423423423423423423', # Recommended parameters 'user_id': 'bridge_user', 'roles': role, 'oauth_callback': 'about:blank', 'context_id': 'bridge_collection' }, } # Check read-only user do not exists read_only_user = BridgeUser.objects.filter(username='******') self.assertFalse(read_only_user) consumer = ToolConsumer(**consumer_prams) response = self.client.post( consumer.launch_url, HTTP_HOST=settings.BRIDGE_HOST, data=consumer.generate_launch_data(), headers={'Content-Type': 'application/x-www-form-urlencoded'}) if role in ['Instructor', 'Administrator']: read_only_user = BridgeUser.objects.filter(username='******') self.assertTrue(read_only_user) self.assertEqual(response.status_code, 302) else: self.assertEqual(response.status_code, 200)
def hxat_lti_launch(locust): target_path = '/lti_init/launch_lti/' consumer = ToolConsumer( consumer_key=os.environ.get('HXAT_CONSUMER', 'fake_consumer_key'), consumer_secret=os.environ.get('HXAT_SECRET', 'fake_secret_key'), launch_url='{}{}'.format(locust.host, target_path), params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": RESOURCE_LINK_ID, "lis_person_sourcedid": os.environ.get('LIS_PERSON_SOURCEDID', 'fake_person'), "lis_outcome_service_url": os.environ.get('LIS_OUTCOME_SERVICE_URL', 'fake_url'), "user_id": USER_ID, "roles": os.environ.get('USER_ROLES', 'fake_role'), "context_id": CONTEXT_ID, }, ) headers = { 'Content-Type': 'application/x-www-form-urlencoded', } params = consumer.generate_launch_data() response = locust.client.post( target_path, catch_response=True, name='/lti_launch/', headers=headers, data=params, verify=locust.verify, ) if response.content == '': response.failure('no data') else: cookie_csrf = response.cookies.get('csrftoken', None) cookie_sid = response.cookies.get('sessionid', None) if not cookie_csrf or not cookie_sid: response.failure('missing csrf and/or session-id cookies') return False else: locust.cookies['UTM_SOURCE'] = cookie_sid locust.cookies['CSRF_TOKEN'] = cookie_csrf response.success() return True
def test_wrong_lti_credentials(self): url = "http://testserver/lti/" consumer = ToolConsumer(consumer_key="foo", consumer_secret="bar", launch_url=url, params={ 'lti_message_type': 'basic-lti-launch-request', 'resource_link_id': 1 }) response = self.c.post(url, consumer.generate_launch_data()) self.assertEqual(403, response.status_code)
def test_wrong_lti_credentials(self): url = "http://testserver/assignments/%s/lti/" % self.open_assignment.pk consumer = ToolConsumer( consumer_key="awilfhawilejfhcbawiehjbcfaliejkwf", consumer_secret="awhlöfhjawköfjhawökefhjwaölkefrk", launch_url=url, params={ 'lti_message_type': 'basic-lti-launch-request', 'resource_link_id': 1 }) response = self.c.post(url, consumer.generate_launch_data()) self.assertEqual(403, response.status_code)
def source_preview(request): """View to render Source content block shared through LTI.""" log.debug("Got request.GET: %s", request.GET) content_source_id = request.GET.get('content_source_id') # pass source_id to get only on content source consumer_prams = { 'consumer_key': '', 'consumer_secret': '', 'params': { # Required parameters 'lti_message_type': 'basic-lti-launch-request', 'lti_version': 'LTI-1p0', 'resource_link_id': 'reaource_link_id', # Recommended parameters 'user_id': 'bridge_user', 'roles': 'Learner', 'oauth_callback': 'about:blank', 'context_id': 'bridge_collection' }, } # Default impersonal consumer parameters are used for getting problem's preview from the Source via LTI sequence_item_id = request.GET.get('sequence_item_id') if content_source_id: # staff flow content_provider = get_content_providers(request, content_source_id).first() if not content_provider: return render(request, 'bridge_lti/stub.html') consumer_prams['consumer_key'] = content_provider.provider_key consumer_prams['consumer_secret'] = content_provider.provider_secret source_name, source_lti_url, consumer_prams = create_lti_launch_params( request, sequence_item_id, consumer_prams) consumer_prams.update({'launch_url': source_lti_url}) log.debug("Sending parameters are: {}".format(consumer_prams)) consumer = ToolConsumer(**consumer_prams) return render( request, 'bridge_lti/content-source.html', { 'launch_data': consumer.generate_launch_data(), 'launch_url': consumer.launch_url, 'source_name': source_name, })
def get_lti_data(course, user_id, task_id): inginious_config = syllabus.get_config()['courses'][course]['inginious'] consumer = ToolConsumer( consumer_key=inginious_config['lti']['consumer_key'], consumer_secret=inginious_config['lti']['consumer_secret'], launch_url='%s/lti/%s/%s' % (inginious_config['url'], inginious_config['course_id'], task_id), params={ 'lti_message_type': 'basic-lti-launch-request', 'lti_version': "1.1", 'resource_link_id': "syllabus_%s" % task_id, 'user_id': user_id, }) d = consumer.generate_launch_data() return d, consumer.launch_url
def test_launchLti_starting_resource(random_assignment_target): course = random_assignment_target["course"] assignment = random_assignment_target["assignment"] target_object = random_assignment_target["target_object"] assignment_target = random_assignment_target["assignment_target"] instructor = random_assignment_target["profile"] course_id = course.course_id resource_link_id = "FakeResourceLinkIDStartingResource" target_path = "/lti_init/launch_lti/" launch_url = "http://testserver{}".format(target_path) lti_resource_link_config = LTIResourceLinkConfig.objects.create( resource_link_id=resource_link_id, assignment_target=assignment_target, ) consumer = ToolConsumer( consumer_key=settings.CONSUMER_KEY, consumer_secret=settings.LTI_SECRET, launch_url=launch_url, params={ "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": resource_link_id, "lis_person_sourcedid": instructor.name, "lis_outcome_service_url": "fake_url", "user_id": instructor.anon_id, "roles": ["Instructor"], "context_id": course_id, "context_title": "{}-title".format(course_id), }, ) params = consumer.generate_launch_data() client = Client(enforce_csrf_checks=False) response = client.post( target_path, data=params, ) assert response.status_code == 302 expected_url = (reverse( "hx_lti_initializer:access_annotation_target", args=[course_id, assignment.assignment_id, target_object.pk], ) + f"?resource_link_id={resource_link_id}" + f"&utm_source={client.session.session_key}") assert response.url == expected_url
def test_working_lti_credentials(self): self.course.lti_key = 'foo' self.course.lti_secret = 'bar' self.course.save() url = "http://testserver/lti/" consumer = ToolConsumer(consumer_key=self.course.lti_key, consumer_secret=self.course.lti_secret, launch_url=url, params={ 'lti_message_type': 'basic-lti-launch-request', 'resource_link_id': 1 }) response = self.c.post(url, consumer.generate_launch_data()) self.assertEqual(302, response.status_code)
def launch(assignment_id: AnyIDType) -> RequestResultType: if (str(current_app.config.get("ENABLE_DEBUG_LAUNCHER")).lower() == "true" and str(current_app.config.get("PRODUCTION")).lower() == "false"): public_url = current_app.config.get("PUBLIC_URL") url = url_for("provider.start") if None in [public_url, url]: raise ConfigurationErrorException( f"Cannot create launch URL from PUBLIC_URL={public_url} and PATH={url}" ) params = dict( lti_message_type="basic-lti-launch-request", lti_version="lti_version", resource_link_id=assignment_id, context_id="Open HPI", user_id="max", roles=["student"], context_title="Open HPI Mooc Neural Networks 2019", context_label="Open HPI NN 2019", lis_person_name_full="Max Mustermann", lis_outcome_service_url="http://localhost:8080/savegrade", ) # Custom args MUST start with custom_ params[current_app.config.get("LAUNCH_ASSIGNMENT_ID_PARAM") or "custom_x-assignment-id"] = assignment_id consumer = ToolConsumer( consumer_key=current_app.config.get("CONSUMER_KEY"), consumer_secret=current_app.config.get("CONSUMER_KEY_SECRET"), launch_url=slash_join(str(public_url), str(url)), params=params, ) return ( render_template( current_app.config.get("TEMPLATE_PREFIX", "") + "launch.html", launch_data=consumer.generate_launch_data(), launch_url=consumer.launch_url, ), 200, MIME.html, ) else: return jsonify(dict(error="The launcher is disabled")), 200, MIME.json
def createParams(self, key, secret, launch_url, resource_link_id, user_id, lis_person_name_full, lis_person_name_given, lis_person_name_family, lis_person_contact_email_primary): params = {} params['lti_message_type'] = 'basic-lti-launch-request' params['lti_version'] = 'LTI-1p0' params['resource_link_id'] = resource_link_id params['user_id'] = user_id params['lis_person_name_full'] = lis_person_name_full params['lis_person_name_given'] = lis_person_name_given params['lis_person_name_family'] = lis_person_name_family params[ 'lis_person_contact_email_primary'] = lis_person_contact_email_primary consumer = ToolConsumer(consumer_key=key, consumer_secret=secret, launch_url=launch_url, params=params) params['launch_data'] = consumer.generate_launch_data() params['launch_url'] = consumer.launch_url return params
def _params_factory( course_id, user_name, user_id, user_roles, resource_link_id, launch_url, course_name=None, with_grade=False, consumer_key=None, consumer_secret=None, tool_consumer_instance_guid=None, ): params = { "lti_message_type": "basic-lti-launch-request", "lti_version": "LTI-1p0", "resource_link_id": resource_link_id, "lis_person_sourcedid": user_name, "user_id": user_id, "roles": user_roles, "context_id": course_id, } if course_name: params["context_title"] = course_name if with_grade: params["lis_outcome_service_url"] = "http://fake_url.com/" params["lis_result_sourcedid"] = "{}:{}:123".format( course_id, resource_link_id) if tool_consumer_instance_guid: params["tool_consumer_instance_guid"] = tool_consumer_instance_guid consumer = ToolConsumer( consumer_key=consumer_key if consumer_key else settings.CONSUMER_KEY, consumer_secret=consumer_secret if consumer_secret else settings.LTI_SECRET, launch_url=launch_url, params=params, ) lti_params = consumer.generate_launch_data() return lti_params
def lti_launch(self, lti_consumer, lti_resource_link_id, assignment_uuid=None, nonce=None, timestamp=None, follow_redirects=True, **kwargs): launch_params = kwargs.copy() launch_params['resource_link_id'] = lti_resource_link_id if assignment_uuid: launch_params['custom_assignment'] = assignment_uuid tool_consumer = ToolConsumer( lti_consumer.oauth_consumer_key, lti_consumer.oauth_consumer_secret, params=launch_params, #launch_url not actually used. Just needed for validation launch_url='http://localhost/api/lti/auth' ) launch_request = tool_consumer.generate_launch_request(nonce=nonce, timestamp=timestamp) launch_data = parse_qs(launch_request.body.decode('utf-8')) rv = self.client.post('/api/lti/auth', data=launch_data, follow_redirects=follow_redirects) yield rv rv.close()
def test_generate_launch_data(self): launch_params = { 'lti_version': 'abc', 'lti_message_type': 'def', 'resource_link_id': '123' } tc = ToolConsumer('client_key', 'client_secret', launch_url='http://example.edu/', params=launch_params) got = tc.generate_launch_data(nonce='wxyz7890', timestamp='2345678901') correct = launch_params.copy() correct.update({ 'oauth_nonce': 'wxyz7890', 'oauth_timestamp': '2345678901', 'oauth_version': '1.0', 'oauth_signature_method': 'HMAC-SHA1', 'oauth_consumer_key': 'client_key', 'oauth_signature': 'gXIAk60dLsrh6YQGT5ZGK6tHDGY=', }) self.assertEqual(got, correct)
def get_lti_data(course, user_id, task_id): course_config = syllabus.get_config()['courses'][course] inginious_config = course_config['inginious'] lti_config = inginious_config['lti'] consumer = ToolConsumer( consumer_key=inginious_config['lti']['consumer_key'], consumer_secret=inginious_config['lti']['consumer_secret'], launch_url='%s/lti/%s/%s' % (inginious_config['url'], inginious_config['course_id'], task_id), params={ 'lti_message_type': 'basic-lti-launch-request', 'lti_version': "1.1", 'resource_link_id': "syllabus_%s" % task_id, 'tool_consumer_instance_name': 'Interactive syllabus (%s)' % course_config['title'], 'tool_consumer_instance_url': lti_config.get('tool_url', None), 'tool_consumer_instance_description': lti_config.get('tool_description', None), 'context_id': lti_config.get('tool_context_id', None), 'context_label': lti_config.get('tool_context_label', None), 'context_title': lti_config.get('tool_context_title', None), 'user_id': user_id, } ) d = consumer.generate_launch_data() return d, consumer.launch_url