Exemplo n.º 1
0
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
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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
Exemplo n.º 5
0
    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
Exemplo n.º 6
0
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
Exemplo n.º 7
0
 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)
Exemplo n.º 8
0
def _get_authorization_header(request, client_key, client_secret):
    """
    Get proper HTTP Authorization header for a given request

    Arguments:
        request: Request object to log Authorization header for

    Returns:
        authorization header
    """
    sha1 = hashlib.sha1()
    body = request.body or ''
    sha1.update(body)
    oauth_body_hash = unicode(
        base64.b64encode(sha1.digest()  # pylint: disable=too-many-function-args
                         ))
    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),
    )
    sig = client.get_oauth_signature(mock_request)
    mock_request.oauth_params.append((u'oauth_signature', sig))

    _, headers, _ = client._render(  # pylint: disable=protected-access
        mock_request)
    return headers['Authorization']
Exemplo n.º 9
0
    def _log_correct_authorization_header(self, request):
        """
        Helper function that logs proper HTTP Authorization header for a given request

        Used only in debug situations, this logs the correct Authorization header based on
        the request header and body according to OAuth 1 Body signing

        Arguments:
            request (xblock.django.request.DjangoWebobRequest):  Request object to log Authorization header for

        Returns:
            nothing
        """
        sha1 = hashlib.sha1()
        sha1.update(request.body)
        oauth_body_hash = unicode(base64.b64encode(sha1.digest()))
        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)
        mock_request = mock.Mock(
            uri=unicode(urllib.unquote(request.url)),
            headers=request.headers,
            body=u"",
            decoded_body=u"",
            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))

        _, headers, _ = client._render(mock_request)  # pylint: disable=protected-access
        log.debug("\n\n#### COPY AND PASTE AUTHORIZATION HEADER ####\n{}\n####################################\n\n"
                  .format(headers['Authorization']))
Exemplo n.º 10
0
def _get_authorization_header(request, client_key, client_secret):
    """
    Get proper HTTP Authorization header for a given request

    Arguments:
        request: Request object to log Authorization header for

    Returns:
        authorization header
    """
    sha1 = hashlib.sha1()
    body = request.body or ''
    sha1.update(body)
    oauth_body_hash = unicode(base64.b64encode(
        sha1.digest()  # pylint: disable=too-many-function-args
    ))
    client = Client(client_key, client_secret)
    params = client.get_oauth_params(request)
    params.append((u'oauth_body_hash', oauth_body_hash))

    blank_request = Request(urllib.unquote(request.url), http_method=request.method, body='', headers=request.headers, encoding='utf_8')
    blank_request.oauth_params = params
    blank_request.decoded_body = ''

    signature = client.get_oauth_signature(blank_request)
    blank_request.oauth_params.append((u'oauth_signature', signature))
    headers = client._render(  # pylint: disable=protected-access
        blank_request
    )[1]
    return headers['Authorization']
Exemplo n.º 11
0
    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
Exemplo n.º 12
0
 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')
Exemplo n.º 13
0
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
Exemplo n.º 14
0
Arquivo: lti.py Projeto: Vilz92/a-plus
 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
Exemplo n.º 15
0
 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)
Exemplo n.º 16
0
 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)
Exemplo n.º 17
0
 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)
Exemplo n.º 18
0
 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
Exemplo n.º 19
0
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
Exemplo n.º 20
0
 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
Exemplo n.º 21
0
    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']
Exemplo n.º 22
0
    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,
        )
Exemplo n.º 23
0
def oauth_client(auth_file):
    from oauthlib.oauth1 import Client

    creds = []
    for idx, line in enumerate(auth_file):
        if idx % 2 == 0:
            continue
        creds.append(line.strip())
    return Client(*creds)
Exemplo n.º 24
0
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']
Exemplo n.º 25
0
    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"]
Exemplo n.º 26
0
    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)
Exemplo n.º 27
0
    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
Exemplo n.º 28
0
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'))
Exemplo n.º 29
0
    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()
Exemplo n.º 30
0
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)
Exemplo n.º 31
0
 def create_client(self, **kwargs):
     return Client(self.consumer_key,
                   signature_method=SIGNATURE_RSA,
                   rsa_key=self.rsa_key,
                   **kwargs)
Exemplo n.º 32
0
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()