mitodl / pylti

PyLTI implementation
BSD 2-Clause "Simplified" License
58 stars 44 forks source link

Issue with Moodle 3.1 #62

Closed dirkcgrunwald closed 8 years ago

dirkcgrunwald commented 8 years ago

I added a comment to a closed issue ( https://github.com/mitodl/pylti/issues/52 ), but wanted to open another because I'm having trouble identifying the problem.

I'm trying to use pylti using the flask demo application and having problems. I am able to use the sample tool provider at http://ltiapps.net/test/tp.php with no problems when Moodle is the tool consumer. Likewise, I can use the sample tool consumer at http://ltiapps.net/test/tc.php against the PyLTI demo tool provider with no problems. The problem arises when using Moodle against the pylti flask demo.

There's a full dump of the debug log below. The problem is that a file (consumer_key.pem) is being checked for validity by the oauth2 library. That file is created in config.py.

The primary difference between my moodle setup and http://ltiapps.net/test/tc.php is that the moodle (http://moodle.cs.colorado.edu) uses HTTPS and the LTIAPPS uses HTTP for the response/grade URL.

make run-lti
Makefile:10: warning: overriding recipe for target 'build-lti'
Makefile:7: warning: ignoring old recipe for target 'build-lti'
docker run --name lti --rm -it --net host --cap-add SYS_PTRACE lti
werkzeug - * Running on http://0.0.0.0:5000/
werkzeug - * Restarting with reloader
pylti.flask - verify request=initial
pylti.flask - {'lti_version': u'LTI-1p0', 'lis_result_sourcedid': u'{"data":{"instanceid":"2","use\ rid":"8","typeid":null,"launchid":193556859},"hash":"bd7c9ddd241a6c766e5be269c4a377feae508ba0f0edb\ bee4915a28074b13f4c"}', 'resource_link_description': u'', 'tool_consumer_info_version': u'20160523\ 00', 'tool_consumer_instance_guid': u'moodle.cs.colorado.edu', 'oauth_signature': u'cioDfvyOZ8A7ur\ CiK7v6UOCwsuQ=', 'context_label': u'test-lti', 'lti_message_type': u'basic-lti-launch-request', 'e\ xt_user_username': u'grunwald', 'lis_person_name_full': u'Dirk Grunwald', 'context_title': u'XXXX \

ylti.common - params {'lti_version': u'LTI-1p0', 'lis_result_sourcedid': u'{"data":{"instanceid":\ "2","userid":"8","typeid":null,"launchid":193556859},"hash":"bd7c9ddd241a6c766e5be269c4a377feae508\ ba0f0edbbee4915a28074b13f4c"}', 'resource_link_description': u'', 'tool_consumer_info_version': u'\ 2016052300', 'tool_consumer_instance_guid': u'moodle.cs.colorado.edu', 'oauth_signature': u'cioDfv\ yOZ8A7urCiK7v6UOCwsuQ=', 'context_label': u'test-lti', 'lti_message_type': u'basic-lti-launch-requ\ est', 'ext_user_username': u'grunwald', 'lis_person_name_full': u'Dirk Grunwald', 'context_title':\ u'XXXX - lti test', 'user_id': u'8', 'tool_consumer_instance_description': u'Computer Science Moo\ dle', 'oauth_consumer_key': u'consumer_key', 'launch_presentation_locale': u'en', 'context_id'\ : u'46', 'lis_outcome_service_url': u'https://moodle.cs.colorado.edu/mod/lti/service.php', 'tool_c\ onsumer_info_product_family_code': u'moodle', 'oauth_callback': u'about:blank', 'lis_person_name_f\ amily': u'Grunwald', 'oauth_nonce': u'408cdf4e9b48be41d1609087fe3bfca6', 'oauth_timestamp': u'1471\ 802462', 'resource_link_title': u'Test-1', 'oauth_signature_method': u'HMAC-SHA1', 'oauth_version'\ : u'1.0', 'lis_course_section_sourcedid': u'', 'lis_person_sourcedid': u'', 'tool_consumer_instanc\ e_name': u'CS-Moodle', 'resource_link_id': u'2', 'lis_person_contact_email_primary': u'dirk.grunwa\ ld@Colorado.EDU', 'roles': u'Instructor', 'context_type': u'CourseSection', 'ext_lms': u'moodle-2'\ , 'lis_person_name_given': u'Dirk', 'launch_presentation_return_url': u'https://moodle.cs.colorado\ .edu/mod/lti/return.php?course=46&launch_container=4&instanceid=2&sesskey=oWz84rvSwo', 'launch_pre\ sentation_document_target': u'window', 'custom_chapter': u'4'}
pylti.flask - verify_request success
pylti.flask - params oauth_consumer_key=consumer_key
pylti.flask - params launch_presentation_return_url=https://moodle.cs.colorado.edu/mod/lti/return.\ php?course=46&launch_container=4&instanceid=2&sesskey=oWz84rvSwo
pylti.flask - params user_id=8
pylti.flask - params oauth_nonce=408cdf4e9b48be41d1609087fe3bfca6
pylti.flask - params context_label=test-lti
pylti.flask - params context_id=46
pylti.flask - params resource_link_title=Test-1
pylti.flask - params resource_link_id=2
pylti.flask - params lis_person_contact_email_primary=dirk.grunwald@Colorado.EDU
pylti.flask - params lis_person_name_full=Dirk Grunwald
pylti.flask - params lis_person_name_family=Grunwald
pylti.flask - params lis_person_name_given=Dirk
pylti.flask - params lis_result_sourcedid={"data":{"instanceid":"2","userid":"8","typeid":null,"la\ unchid":193556859},"hash":"bd7c9ddd241a6c766e5be269c4a377feae508ba0f0edbbee4915a28074b13f4c"}
pylti.flask - params lti_version=LTI-1p0
pylti.flask - params roles=Instructor
pylti.flask - params lis_outcome_service_url=https://moodle.cs.colorado.edu/mod/lti/service.php
pylti.flask - check_role lti_role=Instructor decorator_role=any
werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:02] "POST /lti/ HTTP/1.1" 200 -
ylti.flask - verify request=session
pylti.flask - check_role lti_role=Instructor decorator_role=any
werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:05] "GET /add HTTP/1.1" 200 -
pylti.flask - verify request=session
pylti.flask - check_role lti_role=Instructor decorator_role=any
pylti.common - XML Response:
<?xml version='1.0' encoding='utf-8'?>

V1.0edX_f\ ix{"data":{"instanceid":"2","userid":"8","typeid":nu\ ll,"launchid":193556859},"hash":"bd7c9ddd241a6c766e5be269c4a377feae508ba0f0edbbee4915a28074b13f4c"\ }en0.0 uest> > pylti.common - cert /tmp/app/mit_lti_flask_sample/consumer_key.pem > pylti.common - headers > pylti.common - {'Content-Type': 'application/xml', 'Authorization': u'OAuth realm="https://moodle.\ > cs.colorado.edu", oauth_body_hash="ka%2BLAJhOwIQGAknbSlYL2K9dWT0%3D", oauth_nonce="96631772", oaut\ > h_timestamp="1471802467", oauth_consumer_key="**consumer_key**", oauth_signature_method="HMAC-SHA1\ > ", oauth_version="1.0", oauth_signature="kXNqNa%2BBJX3ijkER0ZgdxSPHfaQ%3D"'} > werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:08] "POST /grade HTTP/1.1" 500 - > Traceback (most recent call last): > File "/usr/lib/python2.7/site-packages/flask/app.py", line 1836, in **call** > return self.wsgi_app(environ, start_response) > File "/usr/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app > response = self.make_response(self.handle_exception(e)) > File "/usr/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception > reraise(exc_type, exc_value, tb) > File "/usr/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app > response = self.full_dispatch_request() > File "/usr/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request > rv = self.handle_user_exception(e) > File "/usr/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception > reraise(exc_type, exc_value, tb) > File "/usr/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request > rv = self.dispatch_request() > File "/usr/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request > return self.view_functions[rule.endpoint](**req.view_args) > File "/usr/lib/python2.7/site-packages/pylti/flask.py", line 363, in wrapper > return function(_args, *_kwargs) > File "/tmp/app/mit_lti_flask_sample/mit_lti_flask_sample.py", line 97, in grade > lti.post_grade(1 if correct else 0) > File "/usr/lib/python2.7/site-packages/pylti/flask.py", line 279, in post_grade > self.response_url, xml) > File "/usr/lib/python2.7/site-packages/pylti/common.py", line 227, in post_message > content_type, > File "/usr/lib/python2.7/site-packages/pylti/common.py", line 194, in _post_patched_request > headers={'Content-Type': content_type}) > File "/usr/lib/python2.7/site-packages/oauth2/__init__.py", line 682, in request > connection_type=connection_type) > File "/usr/lib/python2.7/site-packages/httplib2/**init**.py", line 1464, in request > self.disable_ssl_certificate_validation) > File "/usr/lib/python2.7/site-packages/httplib2/**init**.py", line 929, in **init** > cert_file=cert_file, strict=strict) > File "/usr/lib64/python2.7/httplib.py", line 1220, in **init** > context.load_cert_chain(cert_file, key_file) > SSLError: [SSL] PEM lib (_ssl.c:2738) > werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:08] "GET /grade?__debugger__=yes&cmd=resource&f=st\ > yle.css HTTP/1.1" 200 - > werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:08] "GET /grade?**debugger**=yes&cmd=resource&f=jq\ > uery.js HTTP/1.1" 200 - > werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:08] "GET /grade?**debugger**=yes&cmd=resource&f=de\ > bugger.js HTTP/1.1" 200 - > werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:08] "GET /grade?**debugger**=yes&cmd=resource&f=ub\ > untu.ttf HTTP/1.1" 200 - > werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:08] "GET /grade?**debugger**=yes&cmd=resource&f=co\ > nsole.png HTTP/1.1" 200 - > werkzeug - 50.183.54.209 - - [21/Aug/2016 18:01:08] "GET /grade?**debugger**=yes&cmd=resource&f=so\ > urce.png HTTP/1.1" 200 - > [Dockerfile-lti-centos.txt](https://github.com/mitodl/pylti/files/428996/Dockerfile-lti-centos.txt)
dirkcgrunwald commented 8 years ago

After a bit more time with PDB, I'm finding that commenting out line 170 in pylti/common.py as such:

    if lti_cert:                                                                                   
#        client.add_certificate(key=lti_cert, cert=lti_cert, domain='')                            
        log.debug("cert %s", lti_cert)             

removes the fault. Chasing this down isolates this to config.py, so simply removing config.py resolves the problem, but leaves me uncertain what the CONSUMER_KEY_PEM_FILE is for. Is this simply for having secrets in Heroku without having them visible?

dirkcgrunwald commented 8 years ago

And, after yet more digging, this appears to be an issue with using a LetsEncrypt certificate. When I switched the host to a Comodo certificate, everything worked fine. Presumably some package (httplib2?) installs a certificate list that somehow doesn't include LetsEncrypt.