def test_prepare_headers_ignore_data(self): self.assertEqual( prepare_headers(self.auth_and_data, {}), {u'Authorization': self.norealm_authorization_header}) self.assertEqual( prepare_headers(self.auth_and_data, {}, realm=self.realm), {u'Authorization': self.withrealm_authorization_header})
def test_prepare_headers(self): self.assertEqual( prepare_headers(self.auth_only_params, {}), {u'Authorization': self.norealm_authorization_header}) self.assertEqual( prepare_headers(self.auth_only_params, {}, realm=self.realm), {u'Authorization': self.withrealm_authorization_header})
def test_prepare_headers_ignore_data(self): self.assertEqual( prepare_headers(self.auth_and_data, {}), {'Authorization': self.norealm_authorization_header}) self.assertEqual( prepare_headers(self.auth_and_data, {}, realm=self.realm), {'Authorization': self.withrealm_authorization_header})
def test_prepare_headers(self): self.assertEqual( prepare_headers(self.auth_only_params, {}), {'Authorization': self.norealm_authorization_header}) self.assertEqual( prepare_headers(self.auth_only_params, {}, realm=self.realm), {'Authorization': self.withrealm_authorization_header})
def _oauth_sign(self, url, body, content_type='application/x-www-form-urlencoded', method='POST'): """ Signs request and returns signed Authorization header. """ client_key = self.server.config.get('client_key', self.DEFAULT_CLIENT_KEY) client_secret = self.server.config.get('client_secret', self.DEFAULT_CLIENT_SECRET) client = oauthlib.oauth1.Client( client_key=str(client_key), client_secret=str(client_secret) ) headers = { # This is needed for body encoding: 'Content-Type': content_type, } # Calculate and encode body hash. See http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html sha1 = hashlib.sha1() sha1.update(body.encode('utf-8')) oauth_body_hash = base64.b64encode(sha1.digest()).decode('utf-8') mock_request = mock.Mock( uri=str(six.moves.urllib.parse.unquote(url)), headers=headers, body="", decoded_body="", http_method=str(method), ) params = client.get_oauth_params(mock_request) mock_request.oauth_params = params mock_request.oauth_params.append(('oauth_body_hash', oauth_body_hash)) sig = client.get_oauth_signature(mock_request) mock_request.oauth_params.append(('oauth_signature', sig)) new_headers = parameters.prepare_headers(mock_request.oauth_params, headers, realm=None) return new_headers['Authorization']
def _oauth_sign(self, url, body, content_type=u'application/x-www-form-urlencoded', method=u'POST'): """ Signs request and returns signed Authorization header. """ client_key = self.server.config.get('client_key', self.DEFAULT_CLIENT_KEY) client_secret = self.server.config.get('client_secret', self.DEFAULT_CLIENT_SECRET) client = oauthlib.oauth1.Client( client_key=unicode(client_key), client_secret=unicode(client_secret) ) headers = { # This is needed for body encoding: 'Content-Type': content_type, } # Calculate and encode body hash. See http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html sha1 = hashlib.sha1() sha1.update(body) oauth_body_hash = unicode(base64.b64encode(sha1.digest())) # pylint: disable=too-many-function-args 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), ) 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) return new_headers['Authorization']
def create_authorization_header(self): return prepare_headers(self.params)
def post_grade(sourcedid, outcomes_url, consumer_key, consumer_secret, grade): # Who is treating XML as Text? I am! # WHY WOULD YOU MIX MULTIPART, XML (NOT EVEN JUST XML, BUT WSDL GENERATED POX WTF), AND PARTS OF OAUTH1 SIGNING # IN THE SAME STANDARD AAAA! # TODO: extract this into a real library with real XML parsing # WARNING: You can use this only with data you trust! Beware, etc. post_xml = r""" <?xml version = "1.0" encoding = "UTF-8"?> <imsx_POXEnvelopeRequest xmlns = "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0"> <imsx_POXHeader> <imsx_POXRequestHeaderInfo> <imsx_version>V1.0</imsx_version> <imsx_messageIdentifier>999999123</imsx_messageIdentifier> </imsx_POXRequestHeaderInfo> </imsx_POXHeader> <imsx_POXBody> <replaceResultRequest> <resultRecord> <sourcedGUID> <sourcedId>{sourcedid}</sourcedId> </sourcedGUID> <result> <resultScore> <language>en</language> <textString>{grade}</textString> </resultScore> </result> </resultRecord> </replaceResultRequest> </imsx_POXBody> </imsx_POXEnvelopeRequest> """ post_data = post_xml.format(grade=float(grade), sourcedid=sourcedid) # Yes, we do have to use sha1 :( body_hash_sha = sha1() body_hash_sha.update(post_data.encode('utf-8')) body_hash = base64.b64encode(body_hash_sha.digest()).decode('utf-8') args = { 'oauth_body_hash': body_hash, 'oauth_consumer_key': consumer_key, 'oauth_timestamp': str(time.time()), 'oauth_nonce': str(time.time()) } base_string = signature.construct_base_string( 'POST', signature.normalize_base_string_uri(outcomes_url), signature.normalize_parameters( signature.collect_parameters(body=args, headers={}) ) ) oauth_signature = signature.sign_hmac_sha1(base_string, consumer_secret, None) args['oauth_signature'] = oauth_signature headers = parameters.prepare_headers(args, headers={ 'Content-Type': 'application/xml' }) resp = requests.post(outcomes_url, data=post_data, headers=headers) if resp.status_code != 200: raise GradePostException(resp) response_tree = etree.fromstring(resp.text.encode('utf-8')) # XML and its namespaces. UBOOF! status_tree = response_tree.find('.//{http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0}imsx_statusInfo') code_major = status_tree.find('{http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0}imsx_codeMajor').text if code_major != 'success': raise GradePostException(resp)
async def post_grade(user_id, grade, sourcedid, outcomes_url): # TODO: extract this into a real library with real XML parsing # WARNING: You can use this only with data you trust! Beware, etc. post_xml = r""" <?xml version = "1.0" encoding = "UTF-8"?> <imsx_POXEnvelopeRequest xmlns = "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0"> <imsx_POXHeader> <imsx_POXRequestHeaderInfo> <imsx_version>V1.0</imsx_version> <imsx_messageIdentifier>999999123</imsx_messageIdentifier> </imsx_POXRequestHeaderInfo> </imsx_POXHeader> <imsx_POXBody> <replaceResultRequest> <resultRecord> <sourcedGUID> <sourcedId>{sourcedid}</sourcedId> </sourcedGUID> <result> <resultScore> <language>en</language> <textString>{grade}</textString> </resultScore> </result> </resultRecord> </replaceResultRequest> </imsx_POXBody> </imsx_POXEnvelopeRequest> """ # Assumes these are read in from a config file in Jupyterhub consumer_key = os.environ['LTI_CONSUMER_KEY'] consumer_secret = os.environ['LTI_CONSUMER_SECRET'] sourcedid = "{}:{}".format(sourcedid, user_id) post_data = post_xml.format(grade=float(grade), sourcedid=sourcedid) # Yes, we do have to use sha1 :( body_hash_sha = sha1() body_hash_sha.update(post_data.encode('utf-8')) body_hash = base64.b64encode(body_hash_sha.digest()).decode('utf-8') args = { 'oauth_body_hash': body_hash, 'oauth_consumer_key': consumer_key, 'oauth_timestamp': str(time.time()), 'oauth_nonce': str(time.time()) } base_string = signature.construct_base_string( 'POST', signature.normalize_base_string_uri(outcomes_url), signature.normalize_parameters( signature.collect_parameters(body=args, headers={}))) oauth_signature = signature.sign_hmac_sha1(base_string, consumer_secret, None) args['oauth_signature'] = oauth_signature headers = parameters.prepare_headers( args, headers={'Content-Type': 'application/xml'}) async with async_timeout.timeout(10): async with aiohttp.ClientSession() as session: async with session.post(outcomes_url, data=post_data, headers=headers) as response: resp_text = await response.text() if response.status != 200: raise GradePostException(response) response_tree = etree.fromstring(resp_text.encode('utf-8')) # XML and its namespaces. UBOOF! status_tree = response_tree.find( './/{http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0}imsx_statusInfo' ) code_major = status_tree.find( '{http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0}imsx_codeMajor' ).text if code_major != 'success': raise GradePostException(response)