示例#1
0
 def get_repos(self, account, page_url=None, sess=None, refresh=True):
     if not page_url:
         page_url = self.api_repos_path.format(
             user_id=urlquote(account.user_id),
             user_name=urlquote(account.user_name or ''),
         )
     r = self.api_get(account.domain, page_url, sess=sess)
     repos, count, pages_urls = self.api_paginator(r, self.api_parser(r))
     repos = [
         self.extract_repo_info(repo, account.domain) for repo in repos
     ]
     if repos and repos[0].owner_id != account.user_id:
         # https://hackerone.com/reports/452920
         if not refresh:
             raise TokenExpiredError()
         from liberapay.models.account_elsewhere import UnableToRefreshAccount
         try:
             account = account.refresh_user_info()
         except UnableToRefreshAccount:
             raise TokenExpiredError()
         # Note: we can't pass the page_url below, because it contains the old user_name
         return self.get_repos(account,
                               page_url=None,
                               sess=sess,
                               refresh=False)
     if count == -1 and hasattr(self, 'x_repos_count'):
         count = self.x_repos_count(None, account.extra_info, -1)
     return repos, count, pages_urls
示例#2
0
 def get_repos(self, account, page_url=None, sess=None, refresh=True):
     if not page_url:
         page_url = self.api_repos_path.format(
             user_id=urlquote(account.user_id),
             user_name=urlquote(account.user_name or ''),
         )
     if not getattr(self.api_repos_path, 'use_session', True):
         sess = None
     r = self.api_get(account.domain, page_url, sess=sess)
     repos, count, pages_urls = self.api_paginator(r, self.api_parser(r))
     repos = [self.extract_repo_info(repo) for repo in repos]
     if '{user_id}' in self.api_repos_path:
         for repo in repos:
             if repo.owner_id is None:
                 repo.owner_id = account.user_id
     elif '{user_name}' in self.api_repos_path and repos and repos[
             0].owner_id != account.user_id:
         # https://hackerone.com/reports/452920
         if not refresh:
             raise TokenExpiredError()
         from liberapay.models.account_elsewhere import UnableToRefreshAccount
         try:
             account = account.refresh_user_info()
         except (ElsewhereError, UnableToRefreshAccount):
             raise TokenExpiredError()
         # Note: we can't pass the page_url below, because it contains the old user_name
         return self.get_repos(account,
                               page_url=None,
                               sess=sess,
                               refresh=False)
     return repos, count, pages_urls
    def test_request_refresh_fail(self, mock_request, mock_refresh_token):
        """Test making a request when token fails to be refreshed."""
        mock_request.side_effect = [TokenExpiredError(), TokenExpiredError()]
        mock_refresh_token.return_value = None

        with self.assertRaises(TokenExpiredError):
            self.client.get('https://getfilehub.com/api/endpoint/')
示例#4
0
    def request(self, path, method='get', data=None, files=None, **kwargs):
        """
        General method for submitting an API request

        :param path: the API request path
        :param method: the http request method that should be used
        :param data: dictionary of request data that should be used for post/put requests
        :param files: dictionary of file information when the API accepts file uploads as input
        :param kwargs: optional keyword arguments to be relayed along as request parameters
        :return:
        """
        if data and not files:
            headers = self.json_headers
            request_data = json.dumps(data)
        else:
            headers = self.base_headers
            request_data = data

        request_url = "{0}{1}".format(self.url_base, path)
        request_method = getattr(self.api_client, method)
        try:
            response = request_method(request_url,
                                      data=request_data,
                                      files=files,
                                      params=kwargs,
                                      headers=headers)
            self.status_code = response.status_code
            if self.status_code == 401:
                # if TokenExpiredError is not raised but it should have been, we'll raise it explicitly here
                # https://github.com/oauthlib/oauthlib/pull/506 could cause this code path to be followed.
                # this special handling can likely be removed once https://github.com/oauthlib/oauthlib/pull/506
                # rolls into a new oauthlib release
                raise TokenExpiredError(
                    'Access Token has expired. Please, re-authenticate. '
                    'Use auto_refresh=True to have your client auto refresh')
            return response.json()
        except (TokenUpdated, TokenExpiredError):
            if self.auto_refresh:
                # Re-fetch token and try request again
                self.fetch_access_token(self.code)
                return request_method(request_url,
                                      data=request_data,
                                      files=files,
                                      params=kwargs,
                                      headers=headers).json()
            else:
                self.status_code = 401  # UNAUTHORIZED
                raise TokenExpiredError(
                    'Access Token has expired. Please, re-authenticate. '
                    'Use auto_refresh=True to have your client auto refresh')
    def test_request_refresh(self, mock_request, mock_refresh_token):
        """Test making a request when token needs to be refreshed."""
        callback = Mock()
        response = Mock(spec=requests.Response)
        response.status_code = 200
        mock_request.side_effect = [TokenExpiredError(), response]
        new_token = {
            'access_token': '789',
            'refresh_token': '456',
            'expires_in': '3600',
        }
        mock_refresh_token.return_value = new_token

        client = Client(
            client_id='abc123',
            client_secret='1234',
            uid='abcd',
            url='https://getfilehub.com/',
            refresh_token_callback=callback,
        )

        r = client.get('https://getfilehub.com/api/endpoint/')

        self.assertEqual(200, r.status_code)
        self.assertTrue(callback.called)
        self.assertEqual(new_token, callback.call_args[0][0])
    def test_given_request_return_oauth_token_expired_error_then_except_sequoia_token_expired_error_is_raised(
            self, mock_oauth_request, mock_basic_auth):

        mock_basic_auth.return_value = 'MyBasicAuth'

        mock_oauth_request.side_effect = TokenExpiredError('Token expired')

        auth = ClientGrantAuth('user', 'pass', 'http://identity')

        with pytest.raises(error.TokenExpiredError):
            auth.session.request('GET', 'http://mydata')
示例#7
0
 def get_url(*args):
     """
     Method that simulates the get. When the response is 401 it means that token expired and the
     dispatcher requires another token
     """
     res = MagicMock()
     if args[1].startswith(CONSENT_MANAGER_URI) and self.counter == 0:
         self.counter += 1
         raise TokenExpiredError()
     else:
         res.status_code = 200
     return res
示例#8
0
 def _post(self, endpoint, data):
     """Get data as dictionary from an endpoint."""
     res = self._request("post", endpoint, data=json.dumps(data))
     if not res.content:
         return {}
     try:
         res = res.json()
     except json.JSONDecodeError:
         raise ValueError("Cannot parse {} as JSON".format(res))
     if "error" in res:
         if "code" in res['error'] and res['error']['code'] == 401:
             raise TokenExpiredError()
         else:
             raise SDMError(res["error"])
     return res
示例#9
0
 def test_access_token_refreshed_for_token_expired(self):
     """
     Tests that, when the response is 401 (Unauthorized), another token is created and the call is perfomed again
     """
     with patch('hgw_common.models.OAuth2Session', MockOAuth2Session):
         MockOAuth2Session.RESPONSES = [TokenExpiredError(), 200]
         proxy = OAuth2SessionProxy(self.service_url, self.client_id, self.client_secret)
         m = proxy._session
         first_token = m.token['access_token']
         # m.token['expires_at'] = m.token['expires_at'] - 36001
         proxy.get("/fake_url/1/")
         second_token = m.token['access_token']
         self.assertEqual(len(m.get.call_args_list), 2)  # Number of calls
         self.assertEqual(len(m.fetch_token.call_args_list), 2)  # Number of calls
         m.get.assert_has_calls([call('/fake_url/1/'), call('/fake_url/1/')])
         self.assertEqual(AccessToken.objects.count(), 1)
         self.assertNotEquals(first_token, second_token)
def monzoapi_get_response(self, method, endpoint, params=None, data=None):
    """
    Helper method to handle HTTP requests and catch API errors

    :param method: valid HTTP method
    :type method: str
    :param endpoint: API endpoint
    :type endpoint: str
    :param params: extra parameters passed with the request
    :type params: dict
    :returns: API response
    :rtype: Response
    """
    url = urljoin(self.api_url, endpoint)

    try:
        if method in ['post']:
            response = getattr(self._session, method)(url,
                                                      params=params,
                                                      data=data)
        elif method in ['put']:
            response = getattr(self._session, method)(url, data=data)
        else:
            response = getattr(self._session, method)(url, params=params)

        if response.status_code == 401:
            raise TokenExpiredError()

    except TokenExpiredError:
        # For some reason 'requests-oauthlib' automatic token refreshing
        # doesn't work so we do it here semi-manually
        self._refresh_oath_token()

        self._session = OAuth2Session(
            client_id=self._client_id,
            token=self._token,
        )

        self._get_response(method, endpoint, params, data)

    if response.status_code != requests.codes.ok:
        raise MonzoAPIError("Something went wrong: {}".format(response.json()))

    return response
示例#11
0
 def get_url(*args):
     """
     Method that simulates the get. When the response is 401 it means that token expired and the
     dispatcher requires another token
     """
     res = MagicMock()
     if args[1].startswith(HGW_FRONTEND_URI) and self.counter == 0:
         self.counter += 1
         raise TokenExpiredError()
     else:
         res.status_code = 200
         if args[1].startswith(CONSENT_MANAGER_URI):
             # simulates the consent manager with minimum data just to arrive to the point of
             # getting the hgw_frontend token
             res.json.return_value = {
                 'destination': DESTINATION,
                 'status': 'AC'
             }
     return res
示例#12
0
    def make_request(self, method, url, *args, **kwargs):
        """
        Make HTTP(S) request. Make best effort to detect token expiry.

        Two mechanisms are used for expiry detection:
        1) `oauth_provider`: check expiration datetime on the token itself. This is baked into
            the call to 3rd party's `super().request`. Other tokens are not guaranteed to contain
            this information.
        2) Salesforce: interpret 400 status code along with `invalid_grant` error as token expiry

        Raises:
            TokenExpiredError: upon token expiry detection
        """
        # 1 oauth_provider
        resp = super(OAuth2Client, self).request(method, url, *args, **kwargs)
        # 2 salesforce
        if self.app.authorization_grant_type == Application.GRANT_JWT_BEARER and is_invalid_jwt_grant(resp):
            raise TokenExpiredError(description="400 status code received in JWT flow. Assuming expired token.")
        return resp
示例#13
0
    def request(self, path, method='get', data=None, files=None, **kwargs):
        """
        General method for submitting an API request

        :param path: the API request path
        :param method: the http request method that should be used
        :param data: dictionary of request data that should be used for post/put requests
        :param files: dictionary of file information when the API accepts file uploads as input
        :param kwargs: optional keyword arguments to be relayed along as request parameters
        :return:
        """
        if data and not files:
            headers = self.json_headers
            request_data = json.dumps(data)
        else:
            headers = self.base_headers
            request_data = data

        request_url = "{0}{1}".format(self.url_base, path)
        request_method = getattr(self.api_client, method)
        try:
            response = request_method(request_url,
                                      data=request_data,
                                      files=files,
                                      params=kwargs,
                                      headers=headers)
            self.status_code = response.status_code
            return response.json()
        except (TokenUpdated, TokenExpiredError):
            if self.auto_refresh:
                # Re-fetch token and try request again
                self.fetch_access_token(self.code)
                return request_method(request_url,
                                      data=request_data,
                                      files=files,
                                      params=kwargs,
                                      headers=headers).json()
            else:
                self.status_code = 401  # UNAUTHORIZED
                raise TokenExpiredError(
                    'Access Token has expired. Please, re-authenticate. '
                    'Use auto_refresh=True to have your client auto refresh')
示例#14
0
    def authorize(self, auth):
        """"""
        # check for access token (dict)
        if isinstance(auth, dict):
            # check if access token is still valid
            expires_at = datetime.fromtimestamp(auth.get("expires_at"))
            now = datetime.now()
            if expires_at > now:
                self.access_token = auth
                self.session.headers[
                    "Authorization"] = f"Bearer {self.access_token.get('access_token')}"
                self.metadata = self._metadata()
                return "Authorized!"
            else:
                raise TokenExpiredError("Access token expired!")

        # check for client credentials (tuple)
        if isinstance(auth, tuple):
            client_id, client_secret = auth

            # fetch new access token
            token_url = f"{self.base_url}/oauth/access_token/"
            auth = HTTPBasicAuth(client_id, client_secret)
            client = BackendApplicationClient(client_id=client_id)
            session = OAuth2Session(client=client)

            token_dict = session.fetch_token(token_url=token_url, auth=auth)

            self.access_token = token_dict
            self.session.headers[
                "Authorization"] = f"Bearer {self.access_token.get('access_token')}"
            self.metadata = self._metadata()
            return "Authorized!"
        else:
            raise InvalidClientError(
                "You must provide a valid access token file or client credentials."
            )
示例#15
0
        rsps.add(responses.POST, re.compile(".+google.+"),
            status=200
        )

        with login_disabled_app.test_client() as client:
            response = client.get(
                "/auth/logout"
            )

    assert response.status_code == 302


@pytest.mark.parametrize(
    "error",
    [
        (TokenExpiredError()),
        (HTTPException()),
        (Exception())
    ]
)
def test_logout_controller_token_exception(monkeypatch, mocker, login_disabled_app, error):
    storage = MemoryStorage({"access_token": "fake-token"})
    monkeypatch.setattr(bplogin, "storage", storage)

    mocker.patch("flask_login.utils._get_user", return_value=MagicMock(provider="google", autospec=True))
    with responses.RequestsMock() as rsps:
        rsps.add(responses.POST, re.compile(".+google.+"),
            body=error
        )

        with login_disabled_app.test_client() as client:
 def __handle_expired_token(self, response):
     if ("error" in response and response["error"] == "EXPIRED TOKEN"):
         raise TokenExpiredError(response)