def request(self, method, url, **req_kwargs): ''' A loose wrapper around Requests' :class:`~requests.sessions.Session` which injects OAuth 2.0 parameters. :param method: A string representation of the HTTP method to be used. :type method: str :param url: The resource to be requested. :type url: str :param \*\*req_kwargs: Keyworded args to be passed down to Requests. :type \*\*req_kwargs: dict ''' req_kwargs.setdefault('params', {}) url = self._set_url(url) if is_basestring(req_kwargs['params']): req_kwargs['params'] = dict(parse_qsl(req_kwargs['params'])) if self.access_token and self.openid: req_kwargs['params'].update({ 'access_token': self.access_token, 'openid': self.openid }) req_kwargs.setdefault('timeout', OAUTH2_DEFAULT_TIMEOUT) resp = super(WXSession, self).request(method, url, **req_kwargs) if resp.encoding == 'ISO-8859-1': resp.encoding = 'utf-8' return resp
def request(self, method, url, bearer_auth=True, **req_kwargs): ''' A loose wrapper around Requests' :class:`~requests.sessions.Session` which injects OAuth 2.0 parameters. :param method: A string representation of the HTTP method to be used. :type method: str :param url: The resource to be requested. :type url: str :param bearer_auth: Whether to use Bearer Authentication or not, defaults to `True`. :type bearer_auth: bool :param \*\*req_kwargs: Keyworded args to be passed down to Requests. :type \*\*req_kwargs: dict ''' req_kwargs.setdefault('params', {}) url = self._set_url(url) if is_basestring(req_kwargs['params']): req_kwargs['params'] = dict(parse_qsl(req_kwargs['params'])) if bearer_auth and self.access_token is not None: bearer_token = 'Bearer {token}'.format(token=self.access_token) bearer_header = {'Authorization': bearer_token} req_kwargs.setdefault('headers', {}) req_kwargs['headers'].update(bearer_header) else: req_kwargs['params'].update({self.access_token_key: self.access_token}) req_kwargs.setdefault('timeout', OAUTH2_DEFAULT_TIMEOUT) return super(OAuth2Session, self).request(method, url, **req_kwargs)
def _get_lowered_d(self, d): lowered_d = {} for key in d: if is_basestring(key): lowered_d[key.lower()] = d[key] else: # pragma: no cover lowered_d[key] = d[key] return lowered_d
def _normalize_request_parameters(self, oauth_params, req_kwargs): ''' This process normalizes the request parameters as detailed in the OAuth 1.0 spec. Additionally we apply a `Content-Type` header to the request of the `FORM_URLENCODE` type if the `Content-Type` was previously set, i.e. if this is a `POST` or `PUT` request. This ensures the correct header is set as per spec. Finally we sort the parameters in preparation for signing and return a URL encoded string of all normalized parameters. :param oauth_params: OAuth params to sign with. :type oauth_params: dict :param req_kwargs: Request kwargs to normalize. :type req_kwargs: dict ''' normalized = [] params = req_kwargs.get('params', {}) data = req_kwargs.get('data', {}) headers = req_kwargs.get('headers', {}) # process request parameters for k, v in params.items(): if v is not None: normalized += [(k, v)] # process request data if 'Content-Type' in headers and \ headers['Content-Type'] == FORM_URLENCODED: for k, v in data.items(): normalized += [(k, v)] # extract values from our list of tuples all_normalized = [] for t in normalized: k, v = t if is_basestring(v) and not isinstance(v, bytes): v = v.encode('utf-8') all_normalized += [(k, v)] # add in the params from oauth_params for signing for k, v in oauth_params.items(): if (k, v) in all_normalized: # pragma: no cover continue all_normalized += [(k, v)] # sort the params as per the OAuth 1.0/a spec all_normalized.sort() # finally encode the params as a string return urlencode(all_normalized, True)\ .replace('+', '%20')\ .replace('%7E', '~')
def fake_request(self, method, url, mock_request, ofly_params, user_id=None, hash_meth='sha1', **kwargs): mock_request.return_value = self.response user_id = user_id or self.service.user_id service = OflyService(self.app_id, self.app_secret, name='service', authorize_url=self.authorize_url, base_url=self.base_url) session = service.get_session(self.user_id) r = session.request(method, url, user_id=user_id, hash_meth=hash_meth, **deepcopy(kwargs)) url = self.session._set_url(url) kwargs.setdefault('params', {}) if is_basestring(kwargs['params']): kwargs['params'] = dict(parse_qsl(kwargs['params'])) url_path = urlsplit(url).path signature_base_string = self.service.app_secret + url_path + '?' if len(kwargs['params']): signature_base_string += \ self.fake_get_sorted_params(kwargs['params']) + '&' signature_base_string += self.fake_get_sorted_params(ofly_params) all_params = dict(tuple(ofly_params.items()) + tuple(kwargs['params'].items())) kwargs['params'] = self.fake_get_sorted_params(all_params) if not isinstance(kwargs['params'], bytes): kwargs['params'] = kwargs['params'].encode('utf-8') mock_request.assert_called_with(method, url, timeout=OFLY_DEFAULT_TIMEOUT, **kwargs) return r
def fake_request(self, method, url, mock_request, ofly_params, user_id=None, hash_meth='sha1', **kwargs): mock_request.return_value = self.response user_id = user_id or self.service.user_id service = OflyService(self.app_id, self.app_secret, name='service', authorize_url=self.authorize_url, base_url=self.base_url) session = service.get_session(self.user_id) r = session.request(method, url, user_id=user_id, hash_meth=hash_meth, **deepcopy(kwargs)) url = self.session._set_url(url) kwargs.setdefault('params', {}) if is_basestring(kwargs['params']): kwargs['params'] = dict(parse_qsl(kwargs['params'])) url_path = urlsplit(url).path signature_base_string = self.service.app_secret + url_path + '?' if len(kwargs['params']): signature_base_string += \ self.fake_get_sorted_params(kwargs['params']) + '&' signature_base_string += self.fake_get_sorted_params(ofly_params) all_params = dict( tuple(ofly_params.items()) + tuple(kwargs['params'].items())) kwargs['params'] = self.fake_get_sorted_params(all_params) if not isinstance(kwargs['params'], bytes): kwargs['params'] = kwargs['params'].encode('utf-8') mock_request.assert_called_with(method, url, timeout=OFLY_DEFAULT_TIMEOUT, **kwargs) return r
def request(self, method, url, user_id=None, hash_meth='sha1', **req_kwargs): ''' A loose wrapper around Requests' :class:`~requests.sessions.Session` which injects Ofly parameters. :param method: A string representation of the HTTP method to be used. :type method: str :param url: The resource to be requested. :type url: str :param hash_meth: The hash method to use for signing, defaults to "sha1". :type hash_meth: str :param user_id: The oflyUserid, defaults to `None`. :type user_id: str :param \*\*req_kwargs: Keyworded args to be passed down to Requests. :type \*\*req_kwargs: dict ''' req_kwargs.setdefault('params', {}) req_kwargs.setdefault('timeout', OFLY_DEFAULT_TIMEOUT) url = self._set_url(url) user_id = user_id or self.user_id assert user_id is not None, \ 'An oflyUserid must be provided as `user_id`.' if is_basestring(req_kwargs['params']): req_kwargs['params'] = dict(parse_qsl(req_kwargs['params'])) req_kwargs['params'].update({'oflyUserid': user_id}) params = OflySession.sign(url, self.app_id, self.app_secret, hash_meth=hash_meth, **req_kwargs['params']) # NOTE: Requests can't seem to handle unicode objects, instead we can # encode a string here. req_kwargs['params'] = params if not isinstance(req_kwargs['params'], bytes): req_kwargs['params'] = req_kwargs['params'].encode('utf-8') return super(OflySession, self).request(method, url, **req_kwargs)
def sign(self, consumer_secret, access_token_secret, method, url, oauth_params, req_kwargs): '''Sign request parameters. :param consumer_secret: RSA private key. :type consumer_secret: str or RSA._RSAobj :param access_token_secret: Unused. :type access_token_secret: str :param method: The method of this particular request. :type method: str :param url: The URL of this particular request. :type url: str :param oauth_params: OAuth parameters. :type oauth_params: dict :param req_kwargs: Keyworded args that will be sent to the request method. :type req_kwargs: dict ''' url = self._remove_qs(url) oauth_params = \ self._normalize_request_parameters(oauth_params, req_kwargs) parameters = map(self._escape, [method, url, oauth_params]) # build a Signature Base String signature_base_string = b'&'.join(parameters) # resolve the key if is_basestring(consumer_secret): consumer_secret = self.RSA.importKey(consumer_secret) if not isinstance(consumer_secret, self.RSA._RSAobj): raise ValueError('invalid consumer_secret') # hash the string with RSA-SHA1 s = self.PKCS1_v1_5.new(consumer_secret) # PyCrypto SHA.new requires an encoded byte string h = self.SHA.new(signature_base_string) hashed = s.sign(h) # return the signature return base64.b64encode(hashed).decode()
def sign(self, consumer_secret, access_token_secret, method, url, oauth_params, req_kwargs): '''Sign request parameters. :param consumer_secret: RSA private key. :type consumer_secret: str or RSA._RSAobj :param access_token_secret: Unused. :type access_token_secret: str :param method: The method of this particular request. :type method: str :param url: The URL of this particular request. :type url: str :param oauth_params: OAuth parameters. :type oauth_params: dict :param req_kwargs: Keyworded args that will be sent to the request method. :type req_kwargs: dict ''' url = self._remove_qs(url) oauth_params = \ self._normalize_request_parameters(oauth_params, req_kwargs) parameters = map(self._escape, [method, url, oauth_params]) # build a Signature Base String signature_base_string = b'&'.join(parameters) # resolve the key if is_basestring(consumer_secret): consumer_secret = self.RSA.importKey(consumer_secret) if not isinstance(consumer_secret, self.RSA._RSAobj): raise ValueError("invalid consumer_secret") # hash the string with RSA-SHA1 s = self.PKCS1_v1_5.new(consumer_secret) # PyCrypto SHA.new requires an encoded byte string h = self.SHA.new(signature_base_string) hashed = s.sign(h) # return the signature return base64.b64encode(hashed).decode()
def fake_request(self, method, url, mock_request, bearer_auth=False, **kwargs): mock_request.return_value = self.response url = self.session._set_url(url) service = OAuth2Service(self.client_id, self.client_secret, access_token_url=self.access_token_url, authorize_url=self.authorize_url, base_url=self.base_url) session = service.get_session(self.access_token) r = session.request(method, url, bearer_auth=bearer_auth, **deepcopy(kwargs)) kwargs.setdefault('params', {}) if is_basestring(kwargs.get('params', {})): kwargs['params'] = dict(parse_qsl(kwargs['params'])) if bearer_auth and self.access_token is not None: bearer_token = 'Bearer {token}'.format(token=self.access_token) bearer_header = {'Authorization': bearer_token} kwargs.setdefault('headers', {}) kwargs['headers'].update(bearer_header) else: kwargs['params'].update({'access_token': self.access_token}) mock_request.assert_called_with(method, url, timeout=OAUTH2_DEFAULT_TIMEOUT, **kwargs) return r
def fake_request(self, method, url, mock_request, bearer_auth=False, **kwargs): mock_request.return_value = self.response url = self.session._set_url(url) service = OAuth2Service(self.client_id, self.client_secret, access_token_url=self.access_token_url, authorize_url=self.authorize_url, base_url=self.base_url) session = service.get_session(self.access_token) r = session.request(method, url, bearer_auth=bearer_auth, **deepcopy(kwargs)) kwargs.setdefault('params', {}) if is_basestring(kwargs.get('params', {})): kwargs['params'] = dict(parse_qsl(kwargs['params'])) if bearer_auth and self.access_token is not None: auth = mock_request.call_args[1]['auth'] self.assertEqual(auth.access_token, self.access_token) kwargs['auth'] = auth else: kwargs['params'].update({'access_token': self.access_token}) mock_request.assert_called_with(method, url, timeout=OAUTH2_DEFAULT_TIMEOUT, **kwargs) return r
def request(self, method, url, header_auth=False, realm='', **req_kwargs): ''' A loose wrapper around Requests' :class:`~requests.sessions.Session` which injects OAuth 1.0/a parameters. :param method: A string representation of the HTTP method to be used. :type method: str :param url: The resource to be requested. :type url: str :param header_auth: Authentication via header, defaults to `False.` :type header_auth: bool :param realm: The auth header realm, defaults to ``""``. :type realm: str :param \*\*req_kwargs: Keyworded args to be passed down to Requests. :type \*\*req_kwargs: dict ''' req_kwargs.setdefault('headers', {}) req_kwargs['headers'] = CaseInsensitiveDict(req_kwargs['headers']) url = self._set_url(url) entity_method = method.upper() in ENTITY_METHODS if entity_method: req_kwargs['headers'].setdefault('Content-Type', FORM_URLENCODED) form_urlencoded = \ req_kwargs['headers'].get('Content-Type') == FORM_URLENCODED # inline string conversion if is_basestring(req_kwargs.get('params')): req_kwargs['params'] = dict(parse_qsl(req_kwargs['params'])) if is_basestring(req_kwargs.get('data')) and form_urlencoded: req_kwargs['data'] = dict(parse_qsl(req_kwargs['data'])) req_kwargs.setdefault('timeout', OAUTH1_DEFAULT_TIMEOUT) oauth_params = self._get_oauth_params(req_kwargs) # ensure we always create new instances of dictionary elements for key, value in req_kwargs.items(): if isinstance(value, dict): req_kwargs[key] = deepcopy(value) # sign the request oauth_params['oauth_signature'] = \ self.signature.sign(self.consumer_secret, self.access_token_secret, method, url, oauth_params, req_kwargs) if header_auth and not 'oauth_signature' in \ req_kwargs['headers'].get('Authorization', ''): header = self._get_auth_header(oauth_params, realm) req_kwargs['headers'].update({'Authorization': header}) elif entity_method and not 'oauth_signature' in \ (req_kwargs.get('data') or {}): req_kwargs['data'] = req_kwargs.get('data') or {} # If we have a urlencoded entity-body we should pass the OAuth # parameters on this body. However, if we do not, then we need to # pass these over the request URI, i.e. on params. # # See: # # http://tools.ietf.org/html/rfc5849#section-3.5.2 # # and: # # http://tools.ietf.org/html/rfc5849#section-3.5.3 if form_urlencoded: req_kwargs['data'].update(oauth_params) else: req_kwargs.setdefault('params', {}) req_kwargs['params'].update(oauth_params) elif not 'oauth_signature' in url: req_kwargs.setdefault('params', {}) req_kwargs['params'].update(oauth_params) return super(OAuth1Session, self).request(method, url, **req_kwargs)
def setdefault(self, key, default): if is_basestring(key): key = key.lower() super(CaseInsensitiveDict, self).setdefault(key, default)
def fake_request(self, method, url, mock_request, mock_random, mock_time, mock_sig, header_auth=False, realm='', **kwargs): fake_random = 1 fake_time = 1 fake_sig = 'foo' fake_sig_meth = 'HMAC-SHA1' fake_nonce = sha1(str(fake_random).encode('ascii')).hexdigest() mock_request.return_value = self.response mock_random.return_value = fake_random mock_time.return_value = fake_time mock_sig.return_value = fake_sig method = method url = self.session._set_url(url) service = OAuth1Service(self.consumer_key, self.consumer_secret, name='service', request_token_url=self.request_token_url, access_token_url=self.access_token_url, authorize_url=self.authorize_url, base_url=self.base_url) session = service.get_session((self.access_token, self.access_token_secret)) r = session.request(method, url, header_auth=header_auth, realm=realm, **deepcopy(kwargs)) kwargs.setdefault('headers', {}) kwargs['headers'] = CaseInsensitiveDict(kwargs['headers']) entity_method = method.upper() in ENTITY_METHODS if entity_method: kwargs['headers'].setdefault('Content-Type', FORM_URLENCODED) form_urlencoded = \ kwargs['headers'].get('Content-Type') == FORM_URLENCODED if is_basestring(kwargs.get('params')): kwargs['params'] = dict(parse_qsl(kwargs['params'])) if is_basestring(kwargs.get('data')) and form_urlencoded: kwargs['data'] = dict(parse_qsl(kwargs['data'])) oauth_params = {'oauth_consumer_key': session.consumer_key, 'oauth_nonce': fake_nonce, 'oauth_signature_method': fake_sig_meth, 'oauth_timestamp': fake_time, 'oauth_token': self.access_token, 'oauth_version': session.VERSION, 'oauth_signature': fake_sig} if header_auth: auth = mock_request.call_args[1]['auth'] auth_header = self.fake_get_auth_header(oauth_params, realm=realm) self.assertEqual(auth(requests.Request()).headers['Authorization'], auth_header) kwargs['auth'] = auth elif entity_method: kwargs['data'] = kwargs.get('data') or {} if form_urlencoded: kwargs['data'].update(oauth_params) else: kwargs.setdefault('params', {}) kwargs['params'].update(oauth_params) else: kwargs.setdefault('params', {}) kwargs['params'].update(**oauth_params) mock_request.assert_called_with(method, url, timeout=OAUTH1_DEFAULT_TIMEOUT, **kwargs) return r