1# -*- coding: utf-8 -*- 
    2import logging 
    3 
    4from oauthlib.common import extract_params 
    5from oauthlib.oauth1 import Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER 
    6from oauthlib.oauth1 import SIGNATURE_TYPE_BODY 
    7from requests.utils import to_native_string 
    8from requests.auth import AuthBase 
    9 
    10CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded" 
    11CONTENT_TYPE_MULTI_PART = "multipart/form-data" 
    12 
    13 
    14log = logging.getLogger(__name__) 
    15 
    16# OBS!: Correct signing of requests are conditional on invoking OAuth1 
    17# as the last step of preparing a request, or at least having the 
    18# content-type set properly. 
    19class OAuth1(AuthBase): 
    20    """Signs the request using OAuth 1 (RFC5849)""" 
    21 
    22    client_class = Client 
    23 
    24    def __init__( 
    25        self, 
    26        client_key, 
    27        client_secret=None, 
    28        resource_owner_key=None, 
    29        resource_owner_secret=None, 
    30        callback_uri=None, 
    31        signature_method=SIGNATURE_HMAC, 
    32        signature_type=SIGNATURE_TYPE_AUTH_HEADER, 
    33        rsa_key=None, 
    34        verifier=None, 
    35        decoding="utf-8", 
    36        client_class=None, 
    37        force_include_body=False, 
    38        **kwargs 
    39    ): 
    40 
    41        try: 
    42            signature_type = signature_type.upper() 
    43        except AttributeError: 
    44            pass 
    45 
    46        client_class = client_class or self.client_class 
    47 
    48        self.force_include_body = force_include_body 
    49 
    50        self.client = client_class( 
    51            client_key, 
    52            client_secret, 
    53            resource_owner_key, 
    54            resource_owner_secret, 
    55            callback_uri, 
    56            signature_method, 
    57            signature_type, 
    58            rsa_key, 
    59            verifier, 
    60            decoding=decoding, 
    61            **kwargs 
    62        ) 
    63 
    64    def __call__(self, r): 
    65        """Add OAuth parameters to the request. 
    66 
    67        Parameters may be included from the body if the content-type is 
    68        urlencoded, if no content type is set a guess is made. 
    69        """ 
    70        # Overwriting url is safe here as request will not modify it past 
    71        # this point. 
    72        log.debug("Signing request %s using client %s", r, self.client) 
    73 
    74        content_type = r.headers.get("Content-Type", "") 
    75        if ( 
    76            not content_type 
    77            and extract_params(r.body) 
    78            or self.client.signature_type == SIGNATURE_TYPE_BODY 
    79        ): 
    80            content_type = CONTENT_TYPE_FORM_URLENCODED 
    81        if not isinstance(content_type, str): 
    82            content_type = content_type.decode("utf-8") 
    83 
    84        is_form_encoded = CONTENT_TYPE_FORM_URLENCODED in content_type 
    85 
    86        log.debug( 
    87            "Including body in call to sign: %s", 
    88            is_form_encoded or self.force_include_body, 
    89        ) 
    90 
    91        if is_form_encoded: 
    92            r.headers["Content-Type"] = CONTENT_TYPE_FORM_URLENCODED 
    93            r.url, headers, r.body = self.client.sign( 
    94                str(r.url), str(r.method), r.body or "", r.headers 
    95            ) 
    96        elif self.force_include_body: 
    97            # To allow custom clients to work on non form encoded bodies. 
    98            r.url, headers, r.body = self.client.sign( 
    99                str(r.url), str(r.method), r.body or "", r.headers 
    100            ) 
    101        else: 
    102            # Omit body data in the signing of non form-encoded requests 
    103            r.url, headers, _ = self.client.sign( 
    104                str(r.url), str(r.method), None, r.headers 
    105            ) 
    106 
    107        r.prepare_headers(headers) 
    108        r.url = to_native_string(r.url) 
    109        log.debug("Updated url: %s", r.url) 
    110        log.debug("Updated headers: %s", headers) 
    111        log.debug("Updated body: %r", r.body) 
    112        return r