This file is indexed.

/usr/lib/python3/dist-packages/requests_oauthlib/oauth2_session.py is in python3-requests-oauthlib 0.7.0-0.1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
from __future__ import unicode_literals

import logging

from oauthlib.common import generate_token, urldecode
from oauthlib.oauth2 import WebApplicationClient, InsecureTransportError
from oauthlib.oauth2 import TokenExpiredError, is_secure_transport
import requests

log = logging.getLogger(__name__)


class TokenUpdated(Warning):
    def __init__(self, token):
        super(TokenUpdated, self).__init__()
        self.token = token


class OAuth2Session(requests.Session):
    """Versatile OAuth 2 extension to :class:`requests.Session`.

    Supports any grant type adhering to :class:`oauthlib.oauth2.Client` spec
    including the four core OAuth 2 grants.

    Can be used to create authorization urls, fetch tokens and access protected
    resources using the :class:`requests.Session` interface you are used to.

    - :class:`oauthlib.oauth2.WebApplicationClient` (default): Authorization Code Grant
    - :class:`oauthlib.oauth2.MobileApplicationClient`: Implicit Grant
    - :class:`oauthlib.oauth2.LegacyApplicationClient`: Password Credentials Grant
    - :class:`oauthlib.oauth2.BackendApplicationClient`: Client Credentials Grant

    Note that the only time you will be using Implicit Grant from python is if
    you are driving a user agent able to obtain URL fragments.
    """

    def __init__(self, client_id=None, client=None, auto_refresh_url=None,
            auto_refresh_kwargs=None, scope=None, redirect_uri=None, token=None,
            state=None, token_updater=None, **kwargs):
        """Construct a new OAuth 2 client session.

        :param client_id: Client id obtained during registration
        :param client: :class:`oauthlib.oauth2.Client` to be used. Default is
                       WebApplicationClient which is useful for any
                       hosted application but not mobile or desktop.
        :param scope: List of scopes you wish to request access to
        :param redirect_uri: Redirect URI you registered as callback
        :param token: Token dictionary, must include access_token
                      and token_type.
        :param state: State string used to prevent CSRF. This will be given
                      when creating the authorization url and must be supplied
                      when parsing the authorization response.
                      Can be either a string or a no argument callable.
        :auto_refresh_url: Refresh token endpoint URL, must be HTTPS. Supply
                           this if you wish the client to automatically refresh
                           your access tokens.
        :auto_refresh_kwargs: Extra arguments to pass to the refresh token
                              endpoint.
        :token_updater: Method with one argument, token, to be used to update
                        your token databse on automatic token refresh. If not
                        set a TokenUpdated warning will be raised when a token
                        has been refreshed. This warning will carry the token
                        in its token argument.
        :param kwargs: Arguments to pass to the Session constructor.
        """
        super(OAuth2Session, self).__init__(**kwargs)
        self._client = client or WebApplicationClient(client_id, token=token)
        self.token = token or {}
        self.scope = scope
        self.redirect_uri = redirect_uri
        self.state = state or generate_token
        self._state = state
        self.auto_refresh_url = auto_refresh_url
        self.auto_refresh_kwargs = auto_refresh_kwargs or {}
        self.token_updater = token_updater

        # Allow customizations for non compliant providers through various
        # hooks to adjust requests and responses.
        self.compliance_hook = {
            'access_token_response': set([]),
            'refresh_token_response': set([]),
            'protected_request': set([]),
        }

    def new_state(self):
        """Generates a state string to be used in authorizations."""
        try:
            self._state = self.state()
            log.debug('Generated new state %s.', self._state)
        except TypeError:
            self._state = self.state
            log.debug('Re-using previously supplied state %s.', self._state)
        return self._state

    @property
    def client_id(self):
        return getattr(self._client, "client_id", None)

    @client_id.setter
    def client_id(self, value):
        self._client.client_id = value

    @client_id.deleter
    def client_id(self):
        del self._client.client_id

    @property
    def token(self):
        return getattr(self._client, "token", None)

    @token.setter
    def token(self, value):
        self._client.token = value
        self._client._populate_attributes(value)

    @property
    def access_token(self):
        return getattr(self._client, "access_token", None)

    @access_token.setter
    def access_token(self, value):
        self._client.access_token = value

    @access_token.deleter
    def access_token(self):
        del self._client.access_token

    @property
    def authorized(self):
        """Boolean that indicates whether this session has an OAuth token
        or not. If `self.authorized` is True, you can reasonably expect
        OAuth-protected requests to the resource to succeed. If
        `self.authorized` is False, you need the user to go through the OAuth
        authentication dance before OAuth-protected requests to the resource
        will succeed.
        """
        return bool(self.access_token)

    def authorization_url(self, url, state=None, **kwargs):
        """Form an authorization URL.

        :param url: Authorization endpoint url, must be HTTPS.
        :param state: An optional state string for CSRF protection. If not
                      given it will be generated for you.
        :param kwargs: Extra parameters to include.
        :return: authorization_url, state
        """
        state = state or self.new_state()
        return self._client.prepare_request_uri(url,
                redirect_uri=self.redirect_uri,
                scope=self.scope,
                state=state,
                **kwargs), state

    def fetch_token(self, token_url, code=None, authorization_response=None,
            body='', auth=None, username=None, password=None, method='POST',
            timeout=None, headers=None, verify=True, proxies=None, **kwargs):
        """Generic method for fetching an access token from the token endpoint.

        If you are using the MobileApplicationClient you will want to use
        token_from_fragment instead of fetch_token.

        :param token_url: Token endpoint URL, must use HTTPS.
        :param code: Authorization code (used by WebApplicationClients).
        :param authorization_response: Authorization response URL, the callback
                                       URL of the request back to you. Used by
                                       WebApplicationClients instead of code.
        :param body: Optional application/x-www-form-urlencoded body to add the
                     include in the token request. Prefer kwargs over body.
        :param auth: An auth tuple or method as accepted by requests.
        :param username: Username used by LegacyApplicationClients.
        :param password: Password used by LegacyApplicationClients.
        :param method: The HTTP method used to make the request. Defaults
                       to POST, but may also be GET. Other methods should
                       be added as needed.
        :param headers: Dict to default request headers with.
        :param timeout: Timeout of the request in seconds.
        :param verify: Verify SSL certificate.
        :param kwargs: Extra parameters to include in the token request.
        :return: A token dict
        """
        if not is_secure_transport(token_url):
            raise InsecureTransportError()

        if not code and authorization_response:
            self._client.parse_request_uri_response(authorization_response,
                    state=self._state)
            code = self._client.code
        elif not code and isinstance(self._client, WebApplicationClient):
            code = self._client.code
            if not code:
                raise ValueError('Please supply either code or '
                                 'authorization_response parameters.')


        body = self._client.prepare_request_body(code=code, body=body,
                redirect_uri=self.redirect_uri, username=username,
                password=password, **kwargs)

        client_id = kwargs.get('client_id', '')
        if auth is None:
            if client_id:
                log.debug('Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id)
                client_secret = kwargs.get('client_secret', '')
                client_secret = client_secret if client_secret is not None else ''
                auth = requests.auth.HTTPBasicAuth(client_id, client_secret)
            elif username:
                if password is None:
                    raise ValueError('Username was supplied, but not password.')
                log.debug('Encoding username, password as Basic auth credentials.')
                auth = requests.auth.HTTPBasicAuth(username, password)

        headers = headers or {
            'Accept': 'application/json',
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        }
        self.token = {}
        if method.upper() == 'POST':
            r = self.post(token_url, data=dict(urldecode(body)),
                timeout=timeout, headers=headers, auth=auth,
                verify=verify, proxies=proxies)
            log.debug('Prepared fetch token request body %s', body)
        elif method.upper() == 'GET':
            # if method is not 'POST', switch body to querystring and GET
            r = self.get(token_url, params=dict(urldecode(body)),
                timeout=timeout, headers=headers, auth=auth,
                verify=verify, proxies=proxies)
            log.debug('Prepared fetch token request querystring %s', body)
        else:
            raise ValueError('The method kwarg must be POST or GET.')

        log.debug('Request to fetch token completed with status %s.',
                  r.status_code)
        log.debug('Request headers were %s', r.request.headers)
        log.debug('Request body was %s', r.request.body)
        log.debug('Response headers were %s and content %s.',
                  r.headers, r.text)
        log.debug('Invoking %d token response hooks.',
                  len(self.compliance_hook['access_token_response']))
        for hook in self.compliance_hook['access_token_response']:
            log.debug('Invoking hook %s.', hook)
            r = hook(r)

        self._client.parse_request_body_response(r.text, scope=self.scope)
        self.token = self._client.token
        log.debug('Obtained token %s.', self.token)
        return self.token

    def token_from_fragment(self, authorization_response):
        """Parse token from the URI fragment, used by MobileApplicationClients.

        :param authorization_response: The full URL of the redirect back to you
        :return: A token dict
        """
        self._client.parse_request_uri_response(authorization_response,
                state=self._state)
        self.token = self._client.token
        return self.token

    def refresh_token(self, token_url, refresh_token=None, body='', auth=None,
                      timeout=None, headers=None, verify=True, proxies=None, **kwargs):
        """Fetch a new access token using a refresh token.

        :param token_url: The token endpoint, must be HTTPS.
        :param refresh_token: The refresh_token to use.
        :param body: Optional application/x-www-form-urlencoded body to add the
                     include in the token request. Prefer kwargs over body.
        :param auth: An auth tuple or method as accepted by requests.
        :param timeout: Timeout of the request in seconds.
        :param verify: Verify SSL certificate.
        :param kwargs: Extra parameters to include in the token request.
        :return: A token dict
        """
        if not token_url:
            raise ValueError('No token endpoint set for auto_refresh.')

        if not is_secure_transport(token_url):
            raise InsecureTransportError()

        refresh_token = refresh_token or self.token.get('refresh_token')

        log.debug('Adding auto refresh key word arguments %s.',
                  self.auto_refresh_kwargs)
        kwargs.update(self.auto_refresh_kwargs)
        body = self._client.prepare_refresh_body(body=body,
                refresh_token=refresh_token, scope=self.scope, **kwargs)
        log.debug('Prepared refresh token request body %s', body)

        if headers is None:
            headers = {
                'Accept': 'application/json',
                'Content-Type': (
                    'application/x-www-form-urlencoded;charset=UTF-8'
                ),
            }

        r = self.post(token_url, data=dict(urldecode(body)), auth=auth,
            timeout=timeout, headers=headers, verify=verify, withhold_token=True, proxies=proxies)
        log.debug('Request to refresh token completed with status %s.',
                  r.status_code)
        log.debug('Response headers were %s and content %s.',
                  r.headers, r.text)
        log.debug('Invoking %d token response hooks.',
                  len(self.compliance_hook['refresh_token_response']))
        for hook in self.compliance_hook['refresh_token_response']:
            log.debug('Invoking hook %s.', hook)
            r = hook(r)

        self.token = self._client.parse_request_body_response(r.text, scope=self.scope)
        if not 'refresh_token' in self.token:
            log.debug('No new refresh token given. Re-using old.')
            self.token['refresh_token'] = refresh_token
        return self.token

    def request(self, method, url, data=None, headers=None, withhold_token=False,
                client_id=None, client_secret=None, **kwargs):
        """Intercept all requests and add the OAuth 2 token if present."""
        if not is_secure_transport(url):
            raise InsecureTransportError()
        if self.token and not withhold_token:
            log.debug('Invoking %d protected resource request hooks.',
                      len(self.compliance_hook['protected_request']))
            for hook in self.compliance_hook['protected_request']:
                log.debug('Invoking hook %s.', hook)
                url, headers, data = hook(url, headers, data)

            log.debug('Adding token %s to request.', self.token)
            try:
                url, headers, data = self._client.add_token(url,
                        http_method=method, body=data, headers=headers)
            # Attempt to retrieve and save new access token if expired
            except TokenExpiredError:
                if self.auto_refresh_url:
                    log.debug('Auto refresh is set, attempting to refresh at %s.',
                              self.auto_refresh_url)
                    auth = None
                    if client_id and client_secret:
                        log.debug('Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id)
                        auth = requests.auth.HTTPBasicAuth(client_id, client_secret)
                    token = self.refresh_token(
                        self.auto_refresh_url, auth=auth, **kwargs
                    )
                    if self.token_updater:
                        log.debug('Updating token to %s using %s.',
                                  token, self.token_updater)
                        self.token_updater(token)
                        url, headers, data = self._client.add_token(url,
                                http_method=method, body=data, headers=headers)
                    else:
                        raise TokenUpdated(token)
                else:
                    raise

        log.debug('Requesting url %s using method %s.', url, method)
        log.debug('Supplying headers %s and data %s', headers, data)
        log.debug('Passing through key word arguments %s.', kwargs)
        return super(OAuth2Session, self).request(method, url,
                headers=headers, data=data, **kwargs)

    def register_compliance_hook(self, hook_type, hook):
        """Register a hook for request/response tweaking.

        Available hooks are:
            access_token_response invoked before token parsing.
            refresh_token_response invoked before refresh token parsing.
            protected_request invoked before making a request.

        If you find a new hook is needed please send a GitHub PR request
        or open an issue.
        """
        if hook_type not in self.compliance_hook:
            raise ValueError('Hook type %s is not in %s.',
                             hook_type, self.compliance_hook)
        self.compliance_hook[hook_type].add(hook)