class OAuth1(object): """Signs the request using OAuth 1 (RFC5849)""" def __init__( self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, decoding="utf-8", ): try: signature_type = signature_type.upper() except AttributeError: pass self.client = Client( client_key, client_secret, resource_owner_key, resource_owner_secret, callback_uri, signature_method, signature_type, rsa_key, verifier, decoding=decoding, ) def __call__(self, r): """Add OAuth parameters to the request. Parameters may be included from the body if the content-type is urlencoded, if no content type is set a guess is made. """ # Overwriting url is safe here as request will not modify it past # this point. content_type = r.headers.get("Content-Type".encode("utf-8"), "") if not isinstance(content_type, unicode): content_type = content_type.decode("utf-8") is_form_encoded = CONTENT_TYPE_FORM_URLENCODED in content_type if is_form_encoded or extract_params(r.body): r.headers["Content-Type"] = CONTENT_TYPE_FORM_URLENCODED r.url, r.headers, r.body = self.client.sign(unicode(r.url), unicode(r.method), r.body or "", r.headers) else: # Omit body data in the signing of non form-encoded requests r.url, r.headers, _ = self.client.sign(unicode(r.url), unicode(r.method), None, r.headers) r.url = to_native_str(r.url) return r
def build_oauth_request(self, method, uri, credentials, timestamp, parameters=None, as_query=True): """Build an oauth request given some credentials.""" # oauthlib is requiring the timestamp to be a string, because # it tries to escape all the parameters. oauth_client = Client(credentials['consumer_key'], credentials['consumer_secret'], credentials['token'], credentials['token_secret'], signature_method=(SIGNATURE_PLAINTEXT if self.oauth_sign_plain else SIGNATURE_HMAC), signature_type=(SIGNATURE_TYPE_QUERY if as_query else SIGNATURE_TYPE_AUTH_HEADER), timestamp=str(timestamp)) try: url, signed_headers, body = oauth_client.sign( uri, method, parameters if parameters is not None else {}, {'Content-Type': 'application/x-www-form-urlencoded'}) except ValueError: url, signed_headers, body = oauth_client.sign(uri, method) return url, signed_headers, body
class OAuth1(object): """Signs the request using OAuth 1 (RFC5849)""" def __init__(self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None): try: signature_type = signature_type.upper() except AttributeError: pass self.client = Client(client_key, client_secret, resource_owner_key, resource_owner_secret, callback_uri, signature_method, signature_type, rsa_key, verifier) def __call__(self, r): """Add OAuth parameters to the request. Parameters may be included from the body if the content-type is urlencoded, if no content type is set a guess is made. """ # Overwriting url is safe here as request will not modify it past # this point. is_form_encoded = (CONTENT_TYPE_FORM_URLENCODED in r.headers.get('Content-Type', '')) if is_form_encoded or extract_params(r.body): r.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED r.url, r.headers, r.body = self.client.sign( unicode(r.url), unicode(r.method), r.body or '', r.headers) else: # Omit body data in the signing of non form-encoded requests r.url, r.headers, _ = self.client.sign(unicode(r.url), unicode(r.method), None, r.headers) # Having the authorization header, key or value, in unicode will # result in UnicodeDecodeErrors when the request is concatenated # by httplib. This can easily be seen when attaching files. # Note that simply encoding the value is not enough since Python # saves the type of first key set. Thus we remove and re-add. # >>> d = {u'a':u'foo'} # >>> d['a'] = 'foo' # >>> d # { u'a' : 'foo' } u_header = unicode('Authorization') if u_header in r.headers: auth_header = r.headers[u_header].encode('utf-8') del r.headers[u_header] r.headers['Authorization'] = auth_header return r
class OAuth1(object): """Signs the request using OAuth 1 (RFC5849)""" def __init__(self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, decoding='utf-8'): try: signature_type = signature_type.upper() except AttributeError: pass self.client = Client(client_key, client_secret, resource_owner_key, resource_owner_secret, callback_uri, signature_method, signature_type, rsa_key, verifier, decoding=decoding) def __call__(self, r): """Add OAuth parameters to the request. Parameters may be included from the body if the content-type is urlencoded, if no content type is set a guess is made. """ # Overwriting url is safe here as request will not modify it past # this point. content_type = r.headers.get('Content-Type'.encode('utf-8'), '') if not isinstance(content_type, unicode): content_type = content_type.decode('utf-8') is_form_encoded = (CONTENT_TYPE_FORM_URLENCODED in content_type) if is_form_encoded or extract_params(r.body): r.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED r.url, r.headers, r.body = self.client.sign( unicode(r.url), unicode(r.method), r.body or '', r.headers) else: # Omit body data in the signing of non form-encoded requests r.url, r.headers, _ = self.client.sign(unicode(r.url), unicode(r.method), None, r.headers) r.url = to_native_str(r.url) return r
class OAuth1(object): """Signs the request using OAuth 1 (RFC5849)""" def __init__(self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, decoding='utf-8'): try: signature_type = signature_type.upper() except AttributeError: pass self.client = Client(client_key, client_secret, resource_owner_key, resource_owner_secret, callback_uri, signature_method, signature_type, rsa_key, verifier, decoding=decoding) def __call__(self, r): """Add OAuth parameters to the request. Parameters may be included from the body if the content-type is urlencoded, if no content type is set a guess is made. """ # Overwriting url is safe here as request will not modify it past # this point. is_form_encoded = (CONTENT_TYPE_FORM_URLENCODED in r.headers.get('Content-Type', '')) if is_form_encoded or extract_params(r.body): r.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED r.url, r.headers, r.body = self.client.sign( unicode(r.url), unicode(r.method), r.body or '', r.headers) else: # Omit body data in the signing of non form-encoded requests r.url, r.headers, _ = self.client.sign( unicode(r.url), unicode(r.method), None, r.headers) # Having the authorization header, key or value, in unicode will # result in UnicodeDecodeErrors when the request is concatenated # by httplib. This can easily be seen when attaching files. # Note that simply encoding the value is not enough since Python # saves the type of first key set. Thus we remove and re-add. # >>> d = {u'a':u'foo'} # >>> d['a'] = 'foo' # >>> d # { u'a' : 'foo' } u_header = unicode('Authorization') if u_header in r.headers: auth_header = r.headers[u_header].encode('utf-8') del r.headers[u_header] r.headers['Authorization'] = auth_header return r
def make_api_call(consumer_key, consumer_secret, access_token_key, access_token_secret, method, params, api_url, body=None, headers=None): headers = dict(headers or {}) method = method.upper() params = dict(params, format='json') if method == 'GET': full_url = api_url + "?" + urllib.urlencode(params) elif method == 'POST': full_url = api_url body = urllib.urlencode(params) headers['Content-Type'] = 'application/x-www-form-urlencoded' else: raise ValueError('unsupported HTTP method %r' % method) client = OAClient(consumer_key, client_secret=consumer_secret, resource_owner_key=access_token_key, resource_owner_secret=access_token_secret) full_url, headers, body = client.sign(full_url, method, body, headers) client = httplib2.Http() client.disable_ssl_certificate_validation = True resp, content = client.request(full_url, method=method, body=body, headers=headers) return content
def __init__(self, handler, **kwargs): U1Request.__init__(self, handler, kwargs) self.message.type = protocol_pb2.Message.AUTH_REQUEST self.states = {protocol_pb2.Message.AUTH_AUTHENTICATED: self.authenticated, protocol_pb2.Message.ROOT: self.root} self.end_msg_type = protocol_pb2.Message.ROOT # retrieve our OAuth credentials from file def credentials_from_file(): """Extracts the OAuth credentials from file""" with open(AuthRequest.CREDENTIALS_FILE) as f: jsoncreds = json.loads(f.read()) return jsoncreds oauth_creds = credentials_from_file() # Sign the message with oauth client = Client(oauth_creds["consumer_key"], oauth_creds["consumer_secret"], oauth_creds["token"], oauth_creds["token_secret"], signature_method=SIGNATURE_PLAINTEXT, signature_type=SIGNATURE_TYPE_QUERY) url, headers, body = client.sign('http://server') # Parse out the authentication parameters from the query string. auth_parameters = dict((name, value) for name, value in parse_qsl(urlparse(url).query) if name.startswith('oauth_')) # add the authentication informations to the protobuf for key, value in auth_parameters.items(): newparam = self.message.auth_parameters.add() # create a new parameter newparam.name = key newparam.value = value
def oauth1(self): auth_url = self.url_base + '/session' oauth1_client = Client( self.server_token['consumer_key'], client_secret=self.server_token['consumer_secret'], resource_owner_key=self.server_token['access_token'], resource_owner_secret=self.server_token['access_secret']) uri, headers, body = oauth1_client.sign(auth_url) request = Request(auth_url) request.add_header('Authorization', headers['Authorization']) request.add_header('Content-Type', 'application/json;charset=UTF8') request.add_header('X-Server-Protocol-Version', '2') response = urlopen(request).read() # TODO: catch HTTP errors here, do something useful resp_dict = json.loads(response) self.session_token = resp_dict['auth_session_token'] if self.new_session_callback: self.new_session_callback(self.session_token) return self.session_token
def get_access_token(consumer_key, consumer_secret, req_token_key, req_token_secret, verifier, access_token_url, validate_certs=True): method = 'GET' params = {'format': 'json', 'oauth_callback': 'oob'} # they're really serious about that oob full_url = access_token_url + "&" + urllib.urlencode(params) client = OAClient(consumer_key, client_secret=consumer_secret, resource_owner_key=req_token_key, resource_owner_secret=req_token_secret, verifier=verifier, signature_type=SIGNATURE_TYPE_QUERY) full_url, headers, body = client.sign(full_url, method) client = httplib2.Http() client.disable_ssl_certificate_validation = not validate_certs resp, content = client.request(full_url, method=method) try: resp_dict = json.loads(content) acc_token_key, acc_token_secret = resp_dict['key'], resp_dict['secret'] except: raise ValueError('access token step failed: %s\n\nheaders, etc.: %s' % (content, pformat(resp))) return acc_token_key, acc_token_secret
def sign_request(self, url, method, body, headers): """Sign a request with OAuth credentials.""" # 2012-11-19 BAW: In order to preserve API backward compatibility, # convert empty string body to None. The old python-oauth library # would treat the empty string as "no body", but python-oauthlib # requires None. if not body: content_type = headers.get('Content-Type') if content_type == 'application/x-www-form-urlencoded': body = '' else: body = None # Import oauthlib here so that you don't need it if you're not going # to use it. Plan B: move this out into a separate oauth module. from oauthlib.oauth1 import Client from oauthlib.oauth1.rfc5849 import SIGNATURE_PLAINTEXT oauth_client = Client(self.consumer_key, self.consumer_secret, self.token_key, self.token_secret, signature_method=SIGNATURE_PLAINTEXT, realm=self.oauth_realm) uri, signed_headers, body = oauth_client.sign(url, method, body, headers) headers.update(signed_headers)
def __init__(self, handler, **kwargs): U1Request.__init__(self, handler, kwargs) self.message.type = protocol_pb2.Message.AUTH_REQUEST self.states = { protocol_pb2.Message.AUTH_AUTHENTICATED: self.authenticated, protocol_pb2.Message.ROOT: self.root } self.end_msg_type = protocol_pb2.Message.ROOT # retrieve our OAuth credentials from file def credentials_from_file(): """Extracts the OAuth credentials from file""" with open(AuthRequest.CREDENTIALS_FILE) as f: jsoncreds = json.loads(f.read()) return jsoncreds oauth_creds = credentials_from_file() # Sign the message with oauth client = Client(oauth_creds["consumer_key"], oauth_creds["consumer_secret"], oauth_creds["token"], oauth_creds["token_secret"], signature_method=SIGNATURE_PLAINTEXT, signature_type=SIGNATURE_TYPE_QUERY) url, headers, body = client.sign('http://server') # Parse out the authentication parameters from the query string. auth_parameters = dict( (name, value) for name, value in parse_qsl(urlparse(url).query) if name.startswith('oauth_')) # add the authentication informations to the protobuf for key, value in auth_parameters.items(): newparam = self.message.auth_parameters.add( ) # create a new parameter newparam.name = key newparam.value = value
def launch(CFG, url, post, status=200) : header = {'Content-Type' : 'application/x-www-form-urlencoded'} client = Client(CFG.oauth_consumer_key, client_secret=CFG.oauth_secret, signature_type='BODY') uri, headers, body = client.sign(url, 'POST', post, header) print('\nLaunching to',url,end=' ') r = requests.post(url, data=body, headers=headers, allow_redirects=False) if ( r.status_code == 302 or r.status_code == 303 ) : new_url = r.headers.get('Location', False) if new_url is False: print('No Location header found on redirect') dumpr(r) abort() error_url = post.get('launch_presentation_return_url', False) if ( new_url.startswith(error_url) ) : if ( status == 200 ) : print('Expected a successful launch') dumpr(r) abort() print('Received 302 - Success') return r print('\nFollowing redirect', new_url,end=' ') r = requests.get(new_url, cookies=r.cookies) if ( status != 200 ) : print('Expected a failed launch') dumpr(r) abort() print('Received 200 - Success') return r
def get_login_url(self, request): client = Client(client_key = unicode(self.get_client_key()), client_secret = unicode(self.get_client_secret()), resource_owner_key = u'', resource_owner_secret = u'', callback_uri = unicode(self.get_redirect_url(request)), signature_type = SIGNATURE_TYPE_QUERY) token_url, _token_body, _token_headers = client.sign(unicode(self.get_request_token_uri())) res = requests.get(token_url) res_data = urlparse.parse_qs(res.text) if 'oauth_token' not in res_data: raise BackendError("Oauth provider didn't return access_token. %s" % res.text) request.session[OAUTH_TOKEN_SECRET_KEY] = res_data['oauth_token_secret'][0] authorization_url = self.get_authorize_token_uri() authorization_params = {'oauth_token': res_data['oauth_token'][0], 'oauth_callback': self.get_redirect_url(request)} url_parts = list(urlparse.urlparse(authorization_url)) query = dict(urlparse.parse_qsl(url_parts[4])) query.update(authorization_params) url_parts[4] = urllib.urlencode(query) return urlparse.urlunparse(url_parts)
class OauthRequests: def __init__(self, secret_key, client_key, defaults=None): self.defaults = { "devId": "c55b00b5-dead-beef-cafe-babefac3b001", "user-agent": "Samsung - 4.4.2 - API 19 - 1024x600 Android 4.4.2", "locale": "en" } if defaults: self.defaults.update(defaults) self.secret_key = secret_key self.client_key = client_key self.oauth = Client(client_key, client_secret=secret_key) @cached_request def __call__(self, url, params=None): params = params or {} url = url_set_params(url, params) url, headers, _ = self.oauth.sign(url) headers.update(self.defaults) req = requests.get(url, headers=headers) if req.status_code != 200: logging.error("code %d: %s", req.status_code, req.text) return req
def get_session(self, **kwargs): if self.get_backend_name() in kwargs: auth_obj = kwargs[self.get_backend_name()] request = auth_obj if 'oauth_token' not in request.REQUEST: raise BackendError("Oauth provider didn't return access_token") oauth_token = request.REQUEST.get('oauth_token') oauth_verifier = request.REQUEST.get('oauth_verifier') client = Client(client_key = unicode(self.get_client_key()), client_secret = unicode(self.get_client_secret()), resource_owner_key = unicode(oauth_token), resource_owner_secret = unicode(request.session[OAUTH_TOKEN_SECRET_KEY]), verifier = unicode(oauth_verifier), signature_type = SIGNATURE_TYPE_QUERY) access_url, _access_body, _access_header = client.sign(unicode(self.get_access_token_uri())) res = requests.get(access_url) res_data = urlparse.parse_qs(res.text) if 'oauth_token' not in res_data: raise BackendError("Oauth provider didn't return access_token. %s" % res.text) access_tokens = { 'oauth_token_secret': res_data['oauth_token_secret'][0], 'oauth_token': res_data['oauth_token'][0] } return self._get_session(**access_tokens)
def sign_get_query(self, url=None): client = Client(self.service.consumer_key, client_secret=self.service.consumer_secret, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_QUERY) uri = update_url_params(url or self.service.service.url, self.parameters) query, headers, body = client.sign(uri, http_method="GET") return query
def test_enforce_ssl(self): """Ensure SSL is enforced by default.""" v = RequestValidator() e = BaseEndpoint(v) c = Client('foo') u, h, b = c.sign('http://example.com') r = e._create_request(u, 'GET', b, h) self.assertRaises(errors.InsecureTransportError, e._check_transport_security, r)
def sign_post_parameters(self, url=None): client = Client(self.service.consumer_key, client_secret=self.service.consumer_secret, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_BODY) uri, headers, body = client.sign(url or self.service.url, http_method="POST", body=self.parameters, headers={"Content-Type": "application/x-www-form-urlencoded"}) return urldecode(body)
def sign_post_parameters(self, url=None): client = Client(self.service.consumer_key, client_secret=self.service.consumer_secret, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_BODY) uri, headers, body = client.sign(self._get_url(url), http_method="POST", body=self.parameters, headers={"Content-Type": "application/x-www-form-urlencoded"}) return urldecode(body)
def sign_get_query(self, url=None): client = Client(self.service.consumer_key, client_secret=self.service.consumer_secret, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_QUERY) uri = update_url_params(self._get_url(url), self.parameters) try: query, headers, body = client.sign(uri, http_method="GET") except ValueError as e: raise ValueError("Invalid url %r for %r: %s" % (uri, self.service, e)) return query
async def _connect( self, method, endpoint, params={}, headers=None, body=None ): oauth_client = OAuthClient(self.consumer_key, self.consumer_secret, self.access_token, self.access_token_secret) url = f"https://stream.twitter.com/1.1/{endpoint}.json" url = str(URL(url).with_query(sorted(params.items()))) url, headers, body = oauth_client.sign( url, http_method=method, headers=headers, body=body ) await super()._connect(method, url, headers=headers, body=body)
def getAuthorization(self, method, url, callback=None, verifier=None): client = Client( safe_unicode(self.consumer_key), safe_unicode(self.consumer_secret), safe_unicode(self.key), safe_unicode(self.secret), callback_uri=safe_unicode(callback), verifier=safe_unicode(verifier), ) safe_method = safe_unicode(method) safe_url = safe_unicode(url) # data is omitted because no www-form-encoded data _, header, _ = client.sign(safe_url, safe_method) return header
def xauth(base_url_template=DEFAULT_READER_URL_TEMPLATE, **xargs): """ Returns an OAuth token tuple that can be used with clients.ReaderClient. :param base_url_template: Template for generating Readability API urls. :param consumer_key: Readability consumer key, otherwise read from READABILITY_CONSUMER_KEY. :param consumer_secret: Readability consumer secret, otherwise read from READABILITY_CONSUMER_SECRET. :param username: A username, otherwise read from READABILITY_USERNAME. :param password: A password, otherwise read from READABILITY_PASSWORD. """ consumer_key = xargs.get('consumer_key') or required_from_env( 'READABILITY_CONSUMER_KEY') consumer_secret = xargs.get('consumer_secret') or required_from_env( 'READABILITY_CONSUMER_SECRET') username = xargs.get('username') or required_from_env( 'READABILITY_USERNAME') password = xargs.get('password') or required_from_env( 'READABILITY_PASSWORD') client = Client(consumer_key, client_secret=consumer_secret, signature_type='BODY') url = base_url_template.format(ACCESS_TOKEN_URL) headers = {'Content-Type': 'application/x-www-form-urlencoded'} params = { 'x_auth_username': username, 'x_auth_password': password, 'x_auth_mode': 'client_auth' } uri, headers, body = client.sign(url, http_method='POST', body=urlencode(params), headers=headers) response = requests.post(uri, data=body) logger.debug('POST to %s.', uri) token = parse_qs(response.content) try: # The indexes below are a little weird. parse_qs above gives us # back a dict where each value is a list. We want the first value # in those lists. token = (token[b'oauth_token'][0].decode(), token[b'oauth_token_secret'][0].decode()) except KeyError: raise ValueError('Invalid Credentials.') return token
def getAuthorization(self, request): client = Client( safe_unicode(self.client_key), safe_unicode(self.client_secret), safe_unicode(self.key), safe_unicode(self.secret), callback_uri=safe_unicode(self.callback), verifier=safe_unicode(self.verifier), ) method = safe_unicode(request.get_method()) url = safe_unicode(request.get_full_url()) # data is omitted because no www-form-encoded data uri, headers, body = client.sign(url, method) return headers['Authorization']
def getAuthorization(self, request): client = Client( safe_unicode(self.client_key), safe_unicode(self.client_secret), safe_unicode(self.key), safe_unicode(self.secret), callback_uri=safe_unicode(self.callback), verifier=safe_unicode(self.verifier), ) method = safe_unicode(request.get_method()) url = safe_unicode(request.get_full_url()) # data is omitted because no www-form-encoded data uri, headers, body = client.sign(url, method) return headers["Authorization"]
class YelpAsyncAPI: def __init__(self): # set oauth consumer_key = os.environ["YELP_CONSUMER_KEY"] consumer_secret = os.environ['YELP_CONSUMER_SECRET'] token = os.environ['YELP_TOKEN'] token_secret = os.environ['YELP_TOKEN_SECRET'] if consumer_key is None or consumer_secret is None or token is None or token_secret is None: raise NoKeyError self.client = Client( consumer_key, client_secret=consumer_secret, resource_owner_key=token, resource_owner_secret=token_secret) @asyncio.coroutine def send_query(self, uri, params=None): if params: params = self.clean_params(params) logger.debug("yelp send:%s", params) uri = uri + "?" + params uri, headers, _ = self.client.sign(uri) response = yield from aiohttp.request( 'GET', uri, headers=headers) data = json.loads((yield from response.read()).decode('utf8')) if 'error' in data: logger.debug(data) raise YelpError(msg=data['error']['text']) return data def clean_params(self, params): clean_params = {} for key in params: value = params[key] if value: clean_params[key] = str(value).replace(' ', '+') return urlencode(clean_params) @asyncio.coroutine def search(self, **kwargs): SEARCH_URI = 'http://api.yelp.com/v2/search' params=kwargs data = yield from self.send_query(SEARCH_URI, params=params) return data['businesses']
def xauth(base_url_template=DEFAULT_READER_URL_TEMPLATE, **xargs): """ Returns an OAuth token tuple that can be used with clients.ReaderClient. :param base_url_template: Template for generating Readability API urls. :param consumer_key: Readability consumer key, otherwise read from READABILITY_CONSUMER_KEY. :param consumer_secret: Readability consumer secret, otherwise read from READABILITY_CONSUMER_SECRET. :param username: A username, otherwise read from READABILITY_USERNAME. :param password: A password, otherwise read from READABILITY_PASSWORD. """ consumer_key = xargs.get('consumer_key') or required_from_env('READABILITY_CONSUMER_KEY') consumer_secret = xargs.get('consumer_secret') or required_from_env('READABILITY_CONSUMER_SECRET') username = xargs.get('username') or required_from_env('READABILITY_USERNAME') password = xargs.get('password') or required_from_env('READABILITY_PASSWORD') client = Client(consumer_key, client_secret=consumer_secret, signature_type='BODY') url = base_url_template.format(ACCESS_TOKEN_URL) headers = {'Content-Type': 'application/x-www-form-urlencoded'} params = { 'x_auth_username': username, 'x_auth_password': password, 'x_auth_mode': 'client_auth' } uri, headers, body = client.sign(url, http_method='POST', body=urlencode(params), headers=headers) response = requests.post(uri, data=body) logger.debug('POST to %s.', uri) token = parse_qs(response.content) try: # The indexes below are a little weird. parse_qs above gives us # back a dict where each value is a list. We want the first value # in those lists. token = (token[b'oauth_token'][0].decode(), token[b'oauth_token_secret'][0].decode()) except KeyError: raise ValueError('Invalid Credentials.') return token
def _sign_lti_message(body, key, secret, url): client = Client(client_key=key, client_secret=secret) __, headers, __ = client.sign( unicode(url), http_method=u'POST', body=body, headers={'Content-Type': 'application/x-www-form-urlencoded'}) auth_header = headers['Authorization'][len('OAuth '):] auth = dict([ param.strip().replace('"', '').split('=') for param in auth_header.split(',') ]) body['oauth_nonce'] = auth['oauth_nonce'] body['oauth_signature'] = auth['oauth_signature'] body['oauth_timestamp'] = auth['oauth_timestamp'] body['oauth_signature_method'] = auth['oauth_signature_method'] body['oauth_version'] = auth['oauth_version']
def _sign_lti_message(self, body, key, secret, url): client = Client(client_key=key, client_secret=secret) __, headers, __ = client.sign( url, http_method=u"POST", body=body, headers={"Content-Type": "application/x-www-form-urlencoded"}, ) auth_header = headers["Authorization"][len("OAuth "):] auth = dict([ param.strip().replace('"', "").split("=") for param in auth_header.split(",") ]) body["oauth_nonce"] = auth["oauth_nonce"] body["oauth_signature"] = auth["oauth_signature"] body["oauth_timestamp"] = auth["oauth_timestamp"] body["oauth_signature_method"] = auth["oauth_signature_method"] body["oauth_version"] = auth["oauth_version"]
def _sign_lti_message(body, key, secret, url): client = Client( client_key=key, client_secret=secret ) __, headers, __ = client.sign( unicode(url), http_method=u'POST', body=body, headers={'Content-Type': 'application/x-www-form-urlencoded'} ) auth_header = headers['Authorization'][len('OAuth '):] auth = dict([param.strip().replace('"', '').split('=') for param in auth_header.split(',')]) body['oauth_nonce'] = auth['oauth_nonce'] body['oauth_signature'] = auth['oauth_signature'] body['oauth_timestamp'] = auth['oauth_timestamp'] body['oauth_signature_method'] = auth['oauth_signature_method'] body['oauth_version'] = auth['oauth_version']
class OAuth1(object): '''gets an OAuth 1 (RFC5849) header''' authstr = 'Authorization' def __init__(self, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, decoding='utf-8', **kwargs): kwargs = DotDot(kwargs) if signature_type: signature_type = signature_type.upper() self.client = Client(kwargs.consumer_key, kwargs.consumer_secret, kwargs.access_token_key, kwargs.access_token_secret, callback_uri, signature_method, signature_type, rsa_key, verifier, decoding=decoding) def get_oath_header(self, url, http_method, parms): '''call it to get a recalculated OAuth1 header :param str url: request URL :param str http_method: request method GET|POST|PUT etc....... :param dict parms: request parameters :return: an OAuth 1 header ''' rt = self.client.sign('%s?%s' % (url, urlencode(parms)), http_method=http_method) return "%s: %s" % (self.authstr, rt[1][self.authstr].encode('utf-8'))
def sign_request(self, url, method, body, headers): """Sign a request with OAuth credentials.""" # 2012-11-19 BAW: In order to preserve API backward compatibility, # convert empty string body to None. The old python-oauth library # would treat the empty string as "no body", but python-oauthlib # requires None. if not body: content_type = headers.get('Content-Type') if content_type == 'application/x-www-form-urlencoded': body = '' else: body = None # Import oauthlib here so that you don't need it if you're not going # to use it. Plan B: move this out into a separate oauth module. from oauthlib.oauth1 import Client from oauthlib.oauth1.rfc5849 import SIGNATURE_PLAINTEXT oauth_client = Client(self.consumer_key, self.consumer_secret, self.token_key, self.token_secret, signature_method=SIGNATURE_PLAINTEXT, realm=self.oauth_realm) uri, signed_headers, body = oauth_client.sign( url, method, body, headers) headers.update(signed_headers)
class OAuth1(object): '''gets an OAuth 1 (RFC5849) header''' authstr = 'Authorization' def __init__( self, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, decoding='utf-8', **kwargs): kwargs = DotDot(kwargs) if signature_type: signature_type = signature_type.upper() self.client = Client( kwargs.consumer_key, kwargs.consumer_secret, kwargs.access_token_key, kwargs.access_token_secret, callback_uri, signature_method, signature_type, rsa_key, verifier, decoding=decoding) def get_oath_header(self, url, http_method, parms): '''call it to get a recalculated OAuth1 header :param str url: request URL :param str http_method: request method GET|POST|PUT etc....... :param dict parms: request parameters :return: an OAuth 1 header ''' rt = self.client.sign('%s?%s' % (url, urlencode(parms)), http_method=http_method) return "%s: %s" % (self.authstr, rt[1][self.authstr].encode('utf-8'))
def _get_oauth_headers(self, method, url, data=None, headers=None): """Basic wrapper around oauthlib that we use for Twitter and Flickr.""" # "Client" == "Consumer" in oauthlib parlance. key = self._account.consumer_key secret = self._account.consumer_secret # "resource_owner" == secret and token. resource_owner_key = self._get_access_token() resource_owner_secret = self._account.secret_token oauth_client = Client(key, secret, resource_owner_key, resource_owner_secret) headers = headers or {} if data is not None: headers['Content-Type'] = 'application/x-www-form-urlencoded' # All we care about is the headers, which will contain the # Authorization header necessary to satisfy OAuth. uri, headers, body = oauth_client.sign(url, body=data, headers=headers or {}, http_method=method) return headers
async def _connect(self, method, endpoint, params={}, headers=None, body=None): error_count = 0 # https://developer.twitter.com/en/docs/twitter-api/v1/tweets/filter-realtime/guides/connecting stall_timeout = 90 network_error_wait = network_error_wait_step = 0.25 network_error_wait_max = 16 http_error_wait = http_error_wait_start = 5 http_error_wait_max = 320 http_420_error_wait_start = 60 oauth_client = OAuthClient(self.consumer_key, self.consumer_secret, self.access_token, self.access_token_secret) if self.session is None or self.session.closed: self.session = aiohttp.ClientSession( headers={"User-Agent": self.user_agent}, timeout=aiohttp.ClientTimeout(sock_read=stall_timeout)) url = f"https://stream.twitter.com/1.1/{endpoint}.json" url = str(URL(url).with_query(sorted(params.items()))) try: while error_count <= self.max_retries: request_url, request_headers, request_body = oauth_client.sign( url, method, body, headers) try: async with self.session.request(method, request_url, headers=request_headers, data=request_body, proxy=self.proxy) as resp: if resp.status == 200: error_count = 0 http_error_wait = http_error_wait_start network_error_wait = network_error_wait_step await self.on_connect() async for line in resp.content: line = line.strip() if line: await self.on_data(line) else: await self.on_keep_alive() await self.on_closed(resp) else: await self.on_request_error(resp.status) error_count += 1 if resp.status == 420: if http_error_wait < http_420_error_wait_start: http_error_wait = http_420_error_wait_start await asyncio.sleep(http_error_wait) http_error_wait *= 2 if resp.status != 420: if http_error_wait > http_error_wait_max: http_error_wait = http_error_wait_max except (aiohttp.ClientConnectionError, aiohttp.ClientPayloadError) as e: await self.on_connection_error() await asyncio.sleep(network_error_wait) network_error_wait += network_error_wait_step if network_error_wait > network_error_wait_max: network_error_wait = network_error_wait_max except asyncio.CancelledError: return except Exception as e: await self.on_exception(e) finally: await self.session.close() await self.on_disconnect()
def SignedTestRequest(form=None, consumer=None, token=None, method=None, url=None, callback=None, timestamp=None, verifier=None, signature_type='AUTH_HEADER', raw_body=None, *a, **kw): """\ Creates a signed TestRequest """ def safe_unicode(s): # I really really hate oauthlib's insistence on using unicode # on things that are really bytes. if isinstance(s, str): return unicode(s) return s if not consumer: raise ValueError('consumer must be provided to build a signed request') if form is None: form = {} result = TestRequest(form=form, url=url, method=method, *a, **kw) if raw_body: result.stdin.write(raw_body) url = url or result.getURL() url = safe_unicode(url) method = method and safe_unicode(method) or safe_unicode(result.method) timestamp = timestamp or unicode(int(time())) token_key = token and token.key token_secret = token and token.secret client = Client( safe_unicode(consumer.key), safe_unicode(consumer.secret), safe_unicode(token_key), safe_unicode(token_secret), safe_unicode(callback), verifier=safe_unicode(verifier), timestamp=timestamp, signature_type=signature_type, ) if result.getHeader('Content-Type') == 'application/x-www-form-urlencoded': headers = {'Content-Type': 'application/x-www-form-urlencoded'} url_signed, headers, body = client.sign(url, method, body=raw_body, headers=headers) else: url_signed, headers, body = client.sign(url, method) # lazy not importing oauthlib tokens. if signature_type == 'AUTH_HEADER': result._auth = headers['Authorization'] return result elif signature_type == 'QUERY': qs = urlparse.urlsplit(url_signed).query result = TestRequest(form=form, url=url, QUERY_STRING=qs, *a, **kw) if raw_body: result.stdin.write(raw_body) return result
def get_common_objects(self): super().get_common_objects() user = self.request.user # Determine user ID. student_id = "aplusuid%d" % (user.pk) if self.profile.student_id: student_id = self.profile.student_id # MD5 the user id so that the real student id and names or emails # are not linked in external services. student_id = hashlib.md5(student_id.encode('utf-8')).hexdigest() # Determine user role. role = "Student" if self.is_teacher: role = "Instructor" elif self.is_assistant: role = "TA,TeachingAssistant" parameters = { "lti_version": "LTI-1p0", "lti_message_type": "basic-lti-launch-request", "resource_link_id": "aplus%d" % (self.service.pk), "resource_link_title": self.menu_item.label, # User session. "user_id": student_id, "roles": role, "lis_person_name_full": "%s %s" % (user.first_name, user.last_name), "lis_person_name_given": user.first_name, "lis_person_name_family": user.last_name, "lis_person_contact_email_primary": user.email, # Selected course. "context_id": self.request.get_host() \ + self.instance.get_absolute_url(), "context_title": self.course.name, "context_label": self.course.code, "launch_presentation_locale": get_language(), "tool_consumer_instance_guid": self.request.get_host() + "/aplus", "tool_consumer_instance_name": "A+ LMS", } headers = { "Content-Type": "application/x-www-form-urlencoded", } # Sign the request using OAuth. client = Client(self.service.consumer_key, client_secret=self.service.consumer_secret, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_BODY) uri, headers, body = client.sign(self.service.url, http_method="POST", body=parameters, headers=headers) self.url = uri self.parameters = urldecode(body) self.note("url", "parameters")
class BaseEndpointTest(TestCase): def setUp(self): self.validator = MagicMock(spec=RequestValidator) self.validator.allowed_signature_methods = ['HMAC-SHA1'] self.validator.timestamp_lifetime = 600 self.endpoint = RequestTokenEndpoint(self.validator) self.client = Client('foo', callback_uri='https://c.b/cb') self.uri, self.headers, self.body = self.client.sign( 'https://i.b/request_token') def test_ssl_enforcement(self): uri, headers, _ = self.client.sign('http://i.b/request_token') h, b, s = self.endpoint.create_request_token_response(uri, headers=headers) self.assertEqual(s, 400) self.assertIn('insecure_transport_protocol', b) def test_missing_parameters(self): h, b, s = self.endpoint.create_request_token_response(self.uri) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_signature_methods(self): headers = {} headers['Authorization'] = self.headers['Authorization'].replace( 'HMAC', 'RSA') h, b, s = self.endpoint.create_request_token_response(self.uri, headers=headers) self.assertEqual(s, 400) self.assertIn('invalid_signature_method', b) def test_invalid_version(self): headers = {} headers['Authorization'] = self.headers['Authorization'].replace( '1.0', '2.0') h, b, s = self.endpoint.create_request_token_response(self.uri, headers=headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_expired_timestamp(self): headers = {} for pattern in ('12345678901', '4567890123', '123456789K'): headers['Authorization'] = sub(r'timestamp="\d*k?"', 'timestamp="%s"' % pattern, self.headers['Authorization']) h, b, s = self.endpoint.create_request_token_response( self.uri, headers=headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_client_key_check(self): self.validator.check_client_key.return_value = False h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_noncecheck(self): self.validator.check_nonce.return_value = False h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_enforce_ssl(self): """Ensure SSL is enforced by default.""" v = RequestValidator() e = BaseEndpoint(v) c = Client('foo') u, h, b = c.sign('http://example.com') r = e._create_request(u, 'GET', b, h) self.assertRaises(errors.InsecureTransportError, e._check_transport_security, r) def test_multiple_source_params(self): """Check for duplicate params""" v = RequestValidator() e = BaseEndpoint(v) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/?oauth_signature_method=HMAC-SHA1', 'GET', 'oauth_version=foo', URLENCODED) headers = {'Authorization': 'OAuth oauth_signature="foo"'} headers.update(URLENCODED) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/?oauth_signature_method=HMAC-SHA1', 'GET', 'oauth_version=foo', headers) headers = {'Authorization': 'OAuth oauth_signature_method="foo"'} headers.update(URLENCODED) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/', 'GET', 'oauth_signature=foo', headers) def test_duplicate_params(self): """Ensure params are only supplied once""" v = RequestValidator() e = BaseEndpoint(v) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/?oauth_version=a&oauth_version=b', 'GET', None, URLENCODED) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/', 'GET', 'oauth_version=a&oauth_version=b', URLENCODED) def test_mandated_params(self): """Ensure all mandatory params are present.""" v = RequestValidator() e = BaseEndpoint(v) r = e._create_request( 'https://a.b/', 'GET', 'oauth_signature=a&oauth_consumer_key=b&oauth_nonce', URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) def test_oauth_version(self): """OAuth version must be 1.0 if present.""" v = RequestValidator() e = BaseEndpoint(v) r = e._create_request( 'https://a.b/', 'GET', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_timestamp=a&oauth_signature_method=RSA-SHA1&' 'oauth_version=2.0'), URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) def test_oauth_timestamp(self): """Check for a valid UNIX timestamp.""" v = RequestValidator() e = BaseEndpoint(v) # Invalid timestamp length, must be 10 r = e._create_request( 'https://a.b/', 'GET', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' 'oauth_timestamp=123456789'), URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) # Invalid timestamp age, must be younger than 10 minutes r = e._create_request( 'https://a.b/', 'GET', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' 'oauth_timestamp=1234567890'), URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) # Timestamp must be an integer r = e._create_request( 'https://a.b/', 'GET', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' 'oauth_timestamp=123456789a'), URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) def test_case_insensitive_headers(self): """Ensure headers are case-insensitive""" v = RequestValidator() e = BaseEndpoint(v) r = e._create_request( 'https://a.b', 'POST', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' 'oauth_timestamp=123456789a'), URLENCODED) self.assertIsInstance(r.headers, CaseInsensitiveDict) def test_signature_method_validation(self): """Ensure valid signature method is used.""" body = ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=%s&' 'oauth_timestamp=1234567890') uri = 'https://example.com/' class HMACValidator(RequestValidator): @property def allowed_signature_methods(self): return (SIGNATURE_HMAC, ) v = HMACValidator() e = BaseEndpoint(v) r = e._create_request(uri, 'GET', body % 'RSA-SHA1', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'PLAINTEXT', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'shibboleth', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) class RSAValidator(RequestValidator): @property def allowed_signature_methods(self): return (SIGNATURE_RSA, ) v = RSAValidator() e = BaseEndpoint(v) r = e._create_request(uri, 'GET', body % 'HMAC-SHA1', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'PLAINTEXT', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'shibboleth', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) class PlainValidator(RequestValidator): @property def allowed_signature_methods(self): return (SIGNATURE_PLAINTEXT, ) v = PlainValidator() e = BaseEndpoint(v) r = e._create_request(uri, 'GET', body % 'HMAC-SHA1', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'RSA-SHA1', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'shibboleth', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r)
async def _call_twitter_api_once( client: httpx.Client, api_endpoint: str, params: Dict[str, str], *, oauth_client: oauth1.Client, get_n_tweets: Callable[[Dict[str, Any]], int], get_max_tweet_id: Callable[[Dict[str, Any]], int], get_next_token: Callable[[Dict[str, Any]], Union[int, Optional[str]]], ) -> Tuple[Optional[ResultPart], Optional[Union[int, str]]]: """Send a single request to the Twitter API; return (ResultPart, next_token). If the result has no tweets, return `None`. Otherwise, wrap the result in a `ResultPart`. Undefined behavior if `get_n_tweets()` raises an error, or if Twitter returns non-JSON. For Twitter API v1, "get_next_token" can return the minimum tweet ID. Callers can use that to construct a "max_id" for a subsequent request. """ HEADERS = {"Accept": "application/json"} api_params = urlencode(list(sorted(params.items()))) url = f"https://api.twitter.com/{api_endpoint}?{api_params}" url, headers, body = oauth_client.sign(url, headers=HEADERS) body = io.BytesIO() try: result = await download(url, body, headers=headers, httpx_client=client) except HttpErrorNotSuccess as err: return ( ResultPart( "API-ERROR.lz4", mtime=parsedate_to_datetime( err.response.headers["date"]).timestamp(), api_endpoint=api_endpoint, api_params=api_params, http_status=str(err.response.status_code), body=_lz4_compress(body.getbuffer()), ), None, ) except HttpError as err: return ( ResultPart( "NETWORK-ERROR.json.lz4", mtime=datetime.datetime.utcnow().timestamp(), api_endpoint=api_endpoint, api_params=api_params, body=_lz4_compress( _utf8_json_encode(err.i18n_message._asdict())), ), None, ) # missing HTTP date header? Undefined behavior date_header_value = next(value for key, value in result.headers if key.lower() == "date") # not valid UTF-8 JSON? Undefined behavior data = json.loads(str(body.getvalue(), encoding="utf-8")) # missing JSON fields, or not Array response? Undefined behavior n_tweets = get_n_tweets(data) if n_tweets == 0: return None, None # don't write this API response to the tarfile max_tweet_id = get_max_tweet_id(data) next_token = get_next_token(data) return ( ResultPart( "%d.json.lz4" % max_tweet_id, # invalid date format? Undefined behavior mtime=parsedate_to_datetime(date_header_value).timestamp(), api_endpoint=api_endpoint, api_params=api_params, http_status=str(result.status_code), n_tweets=n_tweets, body=_lz4_compress(body.getbuffer()), ), next_token, )
class TumblrClient(object): api_base_url = 'https://api.tumblr.com/v2/' request_token_url = 'https://www.tumblr.com/oauth/request_token' authorization_url = 'https://www.tumblr.com/oauth/authorize' access_token_url = 'https://www.tumblr.com/oauth/access_token' def __init__(self, consumer_key: str, consumer_secret: str, resource_owner_key: Optional[str] = None, resource_owner_secret: Optional[str] = None, callback_uri: Optional[str] = None, oauth_verifier: Optional[str] = None, debug_mode: Optional[bool] = None): if debug_mode: self.session = aiohttp.ClientSession(trace_configs=[AIOTumblrDebugger(logger=log)]) else: self.session = aiohttp.ClientSession() self.oauth_client = Client( client_key=consumer_key, client_secret=consumer_secret, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret, callback_uri=callback_uri, verifier=oauth_verifier, ) async def fetch_request_token(self) -> Dict[str, str]: log.debug(f'Fetching request token...') _, signed_headers, _ = self.oauth_client.sign(self.request_token_url, 'POST') log.debug(f'Signed headers: {signed_headers}') resp = await self.session.post(self.request_token_url, headers=signed_headers) log.debug(f'Response: {resp.status} {resp.reason}') log.debug(f'To: {resp.method} {resp.real_url.human_repr()}') log.debug(f'Requested as: {resp.request_info.method} {resp.request_info.real_url.human_repr()}') log.debug(f'Request headers: {resp.request_info.headers}') token_raw = await resp.text() log.debug(f'Token response: {token_raw}') token = dict(urldecode(token_raw)) self.oauth_client.resource_owner_key = token['oauth_token'] self.oauth_client.resource_owner_secret = token['oauth_token_secret'] # Set callback to None for future signing calls self.oauth_client.callback_uri = None return token def fetch_authorization_url(self, request_token: str = None) -> str: if not request_token: request_token = self.oauth_client.resource_owner_key return f'{self.authorization_url}?oauth_token={request_token}' def parse_authorization_response(self, url: str) -> Dict[str, str]: token = dict(urldecode(urlparse(url).query)) self.oauth_client.resource_owner_key = token['oauth_token'] self.oauth_client.verifier = token['oauth_verifier'] return token async def fetch_access_token(self, verifier: Optional[str] = None) -> Dict[str, str]: if verifier: self.oauth_client.verifier = verifier if not getattr(self.oauth_client, 'verifier', None): raise ValueError('No client verifier set.') # TODO: implement own exceptions log.debug(f'Fetching access token...') _, signed_headers, _ = self.oauth_client.sign(self.access_token_url, 'POST') log.debug(f'Signed headers: {signed_headers}') resp = await self.session.post(self.access_token_url, headers=signed_headers) log.debug(f'Response: {resp.status} {resp.reason}') log.debug(f'To: {resp.method} {resp.real_url.human_repr()}') log.debug(f'Requested as: {resp.request_info.method} {resp.request_info.real_url.human_repr()}') log.debug(f'Request headers: {resp.request_info.headers}') token_raw = await resp.text() log.debug(f'Token response: {token_raw}') token = dict(urldecode(token_raw)) self.oauth_client.resource_owner_key = token['oauth_token'] self.oauth_client.resource_owner_secret = token['oauth_token_secret'] # Unset verifier self.oauth_client.verifier = None return token async def signed_request(self, method: str, endpoint: str, params: Optional[List[Tuple[str, str]]] = None, data: Optional[Dict[str, str]] = None, json: Optional[Any] = None, headers: Optional[Dict[str, str]] = None, **kwargs) -> aiohttp.ClientResponse: url = self.api_base_url + endpoint if data: _, signed_headers, _ = self.oauth_client.sign( add_params_to_uri(url, params), http_method=method, body=data, headers=headers ) return await self.session.request(method, url, params=params, data=data, headers=signed_headers) elif json: # Since it is JSON, body apparently doesn't matter when signing _, signed_headers, _ = self.oauth_client.sign( add_params_to_uri(url, params), http_method=method, headers=headers ) return await self.session.request(method, url, params=params, json=json, headers=signed_headers) else: _, signed_headers, _ = self.oauth_client.sign( add_params_to_uri(url, params), http_method=method, headers=headers ) return await self.session.request(method, url, params=params, headers=signed_headers) @classmethod def register_extension(cls, extension: Type[Extension]): extension.register(cls) @classmethod def unregister_extension(cls, extension: Type[Extension]): extension.unregister(cls) async def close_connection(self): await self.session.close()
resource_owner_key = '' resource_owner_secret = '' if client_key == '' or client_secret == '': print "Please change your client key and secret in connectXAuth.py header" sys.exit(0) if username == 'USER_NAME' or password == 'USER_PASSWORD': print "Please change username and password in connectXAuth.py header" sys.exit(0) client = Client(client_key, client_secret=client_secret, signature_type=SIGNATURE_TYPE_BODY) headers = {"Content-Type": CONTENT_TYPE_FORM_URLENCODED} body = 'x_auth_mode=client_auth&x_auth_username='******'&x_auth_password='******'oauth_token') resource_owner_secret = oauth_tokens.get('oauth_token_secret') cred = {"client_key": client_key, "client_secret": client_secret, "resource_owner_key": resource_owner_key, "resource_owner_secret": resource_owner_secret} import json with open('credentials.json', 'w') as outfile:
if client_key == '' or client_secret == '': print "Please change your client key and secret in connectXAuth.py header" sys.exit(0) if username == 'USER_NAME' or password == 'USER_PASSWORD': print "Please change username and password in connectXAuth.py header" sys.exit(0) client = Client(client_key, client_secret=client_secret, signature_type=SIGNATURE_TYPE_BODY) headers = {"Content-Type": CONTENT_TYPE_FORM_URLENCODED} body = 'x_auth_mode=client_auth&x_auth_username='******'&x_auth_password='******'oauth_token') resource_owner_secret = oauth_tokens.get('oauth_token_secret') cred = { "client_key": client_key, "client_secret": client_secret, "resource_owner_key": resource_owner_key, "resource_owner_secret": resource_owner_secret
class BaseEndpointTest(TestCase): def setUp(self): self.validator = MagicMock(spec=RequestValidator) self.validator.allowed_signature_methods = ['HMAC-SHA1'] self.validator.timestamp_lifetime = 600 self.endpoint = RequestTokenEndpoint(self.validator) self.client = Client('foo', callback_uri='https://c.b/cb') self.uri, self.headers, self.body = self.client.sign( 'https://i.b/request_token') def test_ssl_enforcement(self): uri, headers, _ = self.client.sign('http://i.b/request_token') h, b, s = self.endpoint.create_request_token_response( uri, headers=headers) self.assertEqual(s, 400) self.assertIn('insecure_transport_protocol', b) def test_missing_parameters(self): h, b, s = self.endpoint.create_request_token_response(self.uri) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_signature_methods(self): headers = {} headers['Authorization'] = self.headers['Authorization'].replace( 'HMAC', 'RSA') h, b, s = self.endpoint.create_request_token_response( self.uri, headers=headers) self.assertEqual(s, 400) self.assertIn('invalid_signature_method', b) def test_invalid_version(self): headers = {} headers['Authorization'] = self.headers['Authorization'].replace( '1.0', '2.0') h, b, s = self.endpoint.create_request_token_response( self.uri, headers=headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_expired_timestamp(self): headers = {} for pattern in ('12345678901', '4567890123', '123456789K'): headers['Authorization'] = sub('timestamp="\d*k?"', 'timestamp="%s"' % pattern, self.headers['Authorization']) h, b, s = self.endpoint.create_request_token_response( self.uri, headers=headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_client_key_check(self): self.validator.check_client_key.return_value = False h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_noncecheck(self): self.validator.check_nonce.return_value = False h, b, s = self.endpoint.create_request_token_response( self.uri, headers=self.headers) self.assertEqual(s, 400) self.assertIn('invalid_request', b) def test_enforce_ssl(self): """Ensure SSL is enforced by default.""" v = RequestValidator() e = BaseEndpoint(v) c = Client('foo') u, h, b = c.sign('http://example.com') r = e._create_request(u, 'GET', b, h) self.assertRaises(errors.InsecureTransportError, e._check_transport_security, r) def test_multiple_source_params(self): """Check for duplicate params""" v = RequestValidator() e = BaseEndpoint(v) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/?oauth_signature_method=HMAC-SHA1', 'GET', 'oauth_version=foo', URLENCODED) headers = {'Authorization': 'OAuth oauth_signature="foo"'} headers.update(URLENCODED) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/?oauth_signature_method=HMAC-SHA1', 'GET', 'oauth_version=foo', headers) headers = {'Authorization': 'OAuth oauth_signature_method="foo"'} headers.update(URLENCODED) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/', 'GET', 'oauth_signature=foo', headers) def test_duplicate_params(self): """Ensure params are only supplied once""" v = RequestValidator() e = BaseEndpoint(v) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/?oauth_version=a&oauth_version=b', 'GET', None, URLENCODED) self.assertRaises(errors.InvalidRequestError, e._create_request, 'https://a.b/', 'GET', 'oauth_version=a&oauth_version=b', URLENCODED) def test_mandated_params(self): """Ensure all mandatory params are present.""" v = RequestValidator() e = BaseEndpoint(v) r = e._create_request('https://a.b/', 'GET', 'oauth_signature=a&oauth_consumer_key=b&oauth_nonce', URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) def test_oauth_version(self): """OAuth version must be 1.0 if present.""" v = RequestValidator() e = BaseEndpoint(v) r = e._create_request('https://a.b/', 'GET', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_timestamp=a&oauth_signature_method=RSA-SHA1&' 'oauth_version=2.0'), URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) def test_oauth_timestamp(self): """Check for a valid UNIX timestamp.""" v = RequestValidator() e = BaseEndpoint(v) # Invalid timestamp length, must be 10 r = e._create_request('https://a.b/', 'GET', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' 'oauth_timestamp=123456789'), URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) # Invalid timestamp age, must be younger than 10 minutes r = e._create_request('https://a.b/', 'GET', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' 'oauth_timestamp=1234567890'), URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) # Timestamp must be an integer r = e._create_request('https://a.b/', 'GET', ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=RSA-SHA1&' 'oauth_timestamp=123456789a'), URLENCODED) self.assertRaises(errors.InvalidRequestError, e._check_mandatory_parameters, r) def test_signature_method_validation(self): """Ensure valid signature method is used.""" body = ('oauth_signature=a&oauth_consumer_key=b&oauth_nonce=c&' 'oauth_version=1.0&oauth_signature_method=%s&' 'oauth_timestamp=1234567890') uri = 'https://example.com/' class HMACValidator(RequestValidator): @property def allowed_signature_methods(self): return (SIGNATURE_HMAC,) v = HMACValidator() e = BaseEndpoint(v) r = e._create_request(uri, 'GET', body % 'RSA-SHA1', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'PLAINTEXT', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'shibboleth', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) class RSAValidator(RequestValidator): @property def allowed_signature_methods(self): return (SIGNATURE_RSA,) v = RSAValidator() e = BaseEndpoint(v) r = e._create_request(uri, 'GET', body % 'HMAC-SHA1', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'PLAINTEXT', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'shibboleth', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) class PlainValidator(RequestValidator): @property def allowed_signature_methods(self): return (SIGNATURE_PLAINTEXT,) v = PlainValidator() e = BaseEndpoint(v) r = e._create_request(uri, 'GET', body % 'HMAC-SHA1', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'RSA-SHA1', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r) r = e._create_request(uri, 'GET', body % 'shibboleth', URLENCODED) self.assertRaises(errors.InvalidSignatureMethodError, e._check_mandatory_parameters, r)