From 03cee389e0869263f5f9977098770495b5216733 Mon Sep 17 00:00:00 2001 From: wajeeha-khalid Date: Wed, 13 Jul 2016 11:15:43 +0500 Subject: [PATCH] update oauthlib version to 1.0.3 --- common/djangoapps/terrain/stubs/lti.py | 6 +- common/djangoapps/third_party_auth/lti.py | 70 ++++++++++--------- .../third_party_auth/tests/specs/test_lti.py | 2 +- common/lib/xmodule/xmodule/lti_2_util.py | 6 +- requirements/edx/base.txt | 2 +- 5 files changed, 46 insertions(+), 40 deletions(-) diff --git a/common/djangoapps/terrain/stubs/lti.py b/common/djangoapps/terrain/stubs/lti.py index 6f62d4e093..edb6137d7e 100644 --- a/common/djangoapps/terrain/stubs/lti.py +++ b/common/djangoapps/terrain/stubs/lti.py @@ -256,16 +256,16 @@ class StubLtiHandler(StubHttpRequestHandler): sha1 = hashlib.sha1() sha1.update(body) oauth_body_hash = unicode(base64.b64encode(sha1.digest())) - params = client.get_oauth_params(None) - params.append((u'oauth_body_hash', oauth_body_hash)) mock_request = mock.Mock( uri=unicode(urllib.unquote(url)), headers=headers, body=u"", decoded_body=u"", - oauth_params=params, http_method=unicode(method), ) + params = client.get_oauth_params(mock_request) + mock_request.oauth_params = params + mock_request.oauth_params.append((u'oauth_body_hash', oauth_body_hash)) sig = client.get_oauth_signature(mock_request) mock_request.oauth_params.append((u'oauth_signature', sig)) new_headers = parameters.prepare_headers(mock_request.oauth_params, headers, realm=None) diff --git a/common/djangoapps/third_party_auth/lti.py b/common/djangoapps/third_party_auth/lti.py index 222f76a388..841ed12496 100644 --- a/common/djangoapps/third_party_auth/lti.py +++ b/common/djangoapps/third_party_auth/lti.py @@ -128,9 +128,15 @@ class LTIAuthBackend(BaseAuth): request = Request( uri=strategy.request.build_absolute_uri(), http_method=strategy.request.method, body=strategy.request.body ) - lti_consumer_key = request.oauth_consumer_key + + try: + lti_consumer_key = request.oauth_consumer_key + except AttributeError: + return None + (lti_consumer_valid, lti_consumer_secret, lti_max_timestamp_age) = cls.load_lti_consumer(lti_consumer_key) current_time = calendar.timegm(time.gmtime()) + return cls._get_validated_lti_params_from_values( request=request, current_time=current_time, lti_consumer_valid=lti_consumer_valid, @@ -148,42 +154,42 @@ class LTIAuthBackend(BaseAuth): # Taking a cue from oauthlib, to avoid leaking information through a timing attack, # we proceed through the entire validation before rejecting any request for any reason. # However, as noted there, the value of doing this is dubious. + try: + base_uri = normalize_base_string_uri(request.uri) + parameters = collect_parameters(uri_query=request.uri_query, body=request.body) + parameters_string = normalize_parameters(parameters) + base_string = construct_base_string(request.http_method, base_uri, parameters_string) - base_uri = normalize_base_string_uri(request.uri) - parameters = collect_parameters(uri_query=request.uri_query, body=request.body) - parameters_string = normalize_parameters(parameters) - base_string = construct_base_string(request.http_method, base_uri, parameters_string) + computed_signature = sign_hmac_sha1(base_string, unicode(lti_consumer_secret), '') + submitted_signature = request.oauth_signature - computed_signature = sign_hmac_sha1(base_string, unicode(lti_consumer_secret), '') - submitted_signature = request.oauth_signature + data = {parameter_value_pair[0]: parameter_value_pair[1] for parameter_value_pair in parameters} - data = {parameter_value_pair[0]: parameter_value_pair[1] for parameter_value_pair in parameters} + def safe_int(value): + """ + Interprets parameter as an int or returns 0 if not possible + """ + try: + return int(value) + except (ValueError, TypeError): + return 0 - def safe_int(value): - """ - Interprets parameter as an int or returns 0 if not possible - """ - try: - return int(value) - except (ValueError, TypeError): - return 0 + oauth_timestamp = safe_int(request.oauth_timestamp) - oauth_timestamp = safe_int(request.oauth_timestamp) - - # As this must take constant time, do not use shortcutting operators such as 'and'. - # Instead, use constant time operators such as '&', which is the bitwise and. - valid = (lti_consumer_valid) - valid = valid & (submitted_signature == computed_signature) - valid = valid & (request.oauth_version == '1.0') - valid = valid & (request.oauth_signature_method == 'HMAC-SHA1') - valid = valid & ('user_id' in data) # Not required by LTI but can't log in without one - valid = valid & (oauth_timestamp >= current_time - lti_max_timestamp_age) - valid = valid & (oauth_timestamp <= current_time) - - if valid: - return data - else: - return None + # As this must take constant time, do not use shortcutting operators such as 'and'. + # Instead, use constant time operators such as '&', which is the bitwise and. + valid = (lti_consumer_valid) + valid = valid & (submitted_signature == computed_signature) + valid = valid & (request.oauth_version == '1.0') + valid = valid & (request.oauth_signature_method == 'HMAC-SHA1') + valid = valid & ('user_id' in data) # Not required by LTI but can't log in without one + valid = valid & (oauth_timestamp >= current_time - lti_max_timestamp_age) + valid = valid & (oauth_timestamp <= current_time) + if valid: + return data + except AttributeError as error: + log.error("'{}' not found.".format(error.message)) + return None @classmethod def load_lti_consumer(cls, lti_consumer_key): diff --git a/common/djangoapps/third_party_auth/tests/specs/test_lti.py b/common/djangoapps/third_party_auth/tests/specs/test_lti.py index 9d7469f282..4b2bb1061b 100644 --- a/common/djangoapps/third_party_auth/tests/specs/test_lti.py +++ b/common/djangoapps/third_party_auth/tests/specs/test_lti.py @@ -121,7 +121,7 @@ class IntegrationTestLTI(testutil.TestCase): def test_reject_bad_login(self): login_response = self.client.post( path=LTI_TPA_LOGIN_URL, content_type=FORM_ENCODED, - data="invalid=login" + data="invalid=login", ) # The user should be redirected to the login page with an error message # (auth_entry defaults to login for this provider) diff --git a/common/lib/xmodule/xmodule/lti_2_util.py b/common/lib/xmodule/xmodule/lti_2_util.py index 8b097a9c5a..0afed3bf24 100644 --- a/common/lib/xmodule/xmodule/lti_2_util.py +++ b/common/lib/xmodule/xmodule/lti_2_util.py @@ -109,16 +109,16 @@ class LTI20ModuleMixin(object): log.debug("[LTI] oauth_body_hash = {}".format(oauth_body_hash)) client_key, client_secret = self.get_client_key_secret() client = Client(client_key, client_secret) - params = client.get_oauth_params(None) - params.append((u'oauth_body_hash', oauth_body_hash)) mock_request = mock.Mock( uri=unicode(urllib.unquote(request.url)), headers=request.headers, body=u"", decoded_body=u"", - oauth_params=params, http_method=unicode(request.method), ) + params = client.get_oauth_params(mock_request) + mock_request.oauth_params = params + mock_request.oauth_params.append((u'oauth_body_hash', oauth_body_hash)) sig = client.get_oauth_signature(mock_request) mock_request.oauth_params.append((u'oauth_signature', sig)) diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 59940e2958..40dfbff4ac 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -65,7 +65,7 @@ mongoengine==0.10.0 MySQL-python==1.2.5 networkx==1.7 nose-xunitmp==0.3.2 -oauthlib==0.7.2 +oauthlib==1.0.3 paramiko==1.9.0 path.py==7.2 piexif==1.0.2