Пример #1
0
    def _execute_token_request(self,
                               data,
                               access_token,
                               expect_refresh_token=True):
        """
        Send the request to acquire or refresh an access token.

        :param data:
            Dictionary containing the request parameters as specified by the Box API.
        :type data:
            `dict`
        :param access_token:
            The current access token.
        :type access_token:
            `unicode` or None
        :return:
            The response for the token request.
        :rtype:
            :class:`TokenResponse`
        """
        self._check_closed()
        url = '{base_auth_url}/token'.format(
            base_auth_url=self._api_config.OAUTH2_API_URL)
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        network_response = self._network_layer.request(
            'POST',
            url,
            data=data,
            headers=headers,
            access_token=access_token,
        )
        if not network_response.ok:
            raise BoxOAuthException(network_response.status_code,
                                    network_response.content, url, 'POST',
                                    network_response)
        try:
            token_response = TokenResponse(network_response.json())
        except ValueError:
            raise BoxOAuthException(network_response.status_code,
                                    network_response.content, url, 'POST',
                                    network_response)

        if ('access_token' not in token_response) or (expect_refresh_token
                                                      and 'refresh_token'
                                                      not in token_response):
            raise BoxOAuthException(network_response.status_code,
                                    network_response.content, url, 'POST',
                                    network_response)

        return token_response
Пример #2
0
 def revoke(self):
     """
     Revoke the authorization for the current access/refresh token pair.
     """
     with self._refresh_lock:
         access_token, refresh_token = self._get_and_update_current_tokens()
         token_to_revoke = access_token or refresh_token
         if token_to_revoke is None:
             return
         url = '{base_auth_url}/revoke'.format(
             base_auth_url=API.OAUTH2_API_URL)
         network_response = self._network_layer.request(
             'POST',
             url,
             data={
                 'client_id': self._client_id,
                 'client_secret': self._client_secret,
                 'token': token_to_revoke,
             },
             access_token=access_token,
         )
         if not network_response.ok:
             raise BoxOAuthException(network_response.status_code,
                                     network_response.content, url, 'POST')
         self._store_tokens(None, None)
Пример #3
0
def test_auth_retry_for_invalid_exp_claim(
    jwt_auth_init_mocks,
    expect_auth_retry,
    unsuccessful_jwt_response,
    box_datetime,
):
    # pylint:disable=redefined-outer-name
    enterprise_id = 'fake_enterprise_id'
    with jwt_auth_init_mocks(assert_authed=False) as params:
        auth = params[0]
        with patch.object(auth,
                          '_construct_and_send_jwt_auth') as mock_send_jwt:
            mock_send_jwt.side_effect = [
                BoxOAuthException(400,
                                  network_response=unsuccessful_jwt_response),
                'jwt_token'
            ]
            if not expect_auth_retry:
                with pytest.raises(BoxOAuthException):
                    auth.authenticate_instance(enterprise_id)
            else:
                auth.authenticate_instance(enterprise_id)
            expected_calls = [call(enterprise_id, 'enterprise')]
            if expect_auth_retry:
                expected_calls.append(
                    call(enterprise_id, 'enterprise',
                         box_datetime.replace(microsecond=0, tzinfo=None)))
            assert len(mock_send_jwt.mock_calls) == len(expected_calls)
            mock_send_jwt.assert_has_calls(expected_calls)
Пример #4
0
def test_auth_max_retries_for_internal_server_error(
    jwt_auth_init_mocks,
    unsuccessful_jwt_response,
):
    # pylint:disable=redefined-outer-name
    enterprise_id = 'fake_enterprise_id'
    with jwt_auth_init_mocks(assert_authed=False) as params:
        auth = params[0]
        with patch.object(auth,
                          '_construct_and_send_jwt_auth') as mock_send_jwt:
            side_effect = []
            expected_calls = []
            # Retries max number of times, then throws the error
            for _ in range(API.MAX_RETRY_ATTEMPTS + 1):
                side_effect.append(
                    BoxOAuthException(
                        500, network_response=unsuccessful_jwt_response))
                expected_calls.append(call(enterprise_id, 'enterprise', None))
            mock_send_jwt.side_effect = side_effect

            with pytest.raises(BoxOAuthException) as error:
                auth.authenticate_instance(enterprise_id)
            assert error.value.status == 500
            assert len(mock_send_jwt.mock_calls) == len(expected_calls)
            mock_send_jwt.assert_has_calls(expected_calls)
Пример #5
0
def test_auth_retry_for_internal_server_error(
    jwt_auth_init_mocks,
    unsuccessful_jwt_response,
):
    # pylint:disable=redefined-outer-name
    enterprise_id = 'fake_enterprise_id'
    with jwt_auth_init_mocks(assert_authed=False) as params:
        auth = params[0]
        with patch.object(auth,
                          '_construct_and_send_jwt_auth') as mock_send_jwt:
            side_effect = []
            expected_calls = []
            # Retries multiple times, but less than max retries. Then succeeds when it gets a token.
            for _ in range(API.MAX_RETRY_ATTEMPTS - 2):
                side_effect.append(
                    BoxOAuthException(
                        500, network_response=unsuccessful_jwt_response))
                expected_calls.append(call(enterprise_id, 'enterprise', None))
            side_effect.append('jwt_token')
            expected_calls.append(call(enterprise_id, 'enterprise', None))
            mock_send_jwt.side_effect = side_effect

            auth.authenticate_instance(enterprise_id)
            assert len(mock_send_jwt.mock_calls) == len(expected_calls)
            mock_send_jwt.assert_has_calls(expected_calls)
Пример #6
0
    def send_token_request(self,
                           data,
                           access_token,
                           expect_refresh_token=True):
        """
        Send the request to acquire or refresh an access token.

        :param data:
            Dictionary containing the request parameters as specified by the Box API.
        :type data:
            `dict`
        :param access_token:
            The current access token.
        :type access_token:
            `unicode` or None
        :return:
            The access token and refresh token.
        :rtype:
            (`unicode`, `unicode`)
        """
        url = '{base_auth_url}/token'.format(base_auth_url=API.OAUTH2_API_URL)
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        network_response = self._network_layer.request(
            'POST',
            url,
            data=data,
            headers=headers,
            access_token=access_token,
        )
        if not network_response.ok:
            raise BoxOAuthException(network_response.status_code,
                                    network_response.content, url, 'POST')
        try:
            response = network_response.json()
            access_token = response['access_token']
            refresh_token = response.get('refresh_token', None)
            if refresh_token is None and expect_refresh_token:
                raise BoxOAuthException(network_response.status_code,
                                        network_response.content, url, 'POST')
        except (ValueError, KeyError):
            raise BoxOAuthException(network_response.status_code,
                                    network_response.content, url, 'POST')
        self._store_tokens(access_token, refresh_token)
        return self._access_token, self._refresh_token
Пример #7
0
def test_auth_object_is_closed_even_if_revoke_fails(client_id, client_secret,
                                                    access_token,
                                                    mock_box_session):
    auth = OAuth2(client_id=client_id,
                  client_secret=client_secret,
                  access_token=access_token,
                  session=mock_box_session)
    with patch.object(auth,
                      'revoke',
                      side_effect=BoxOAuthException(status=500)):
        with pytest.raises(BoxOAuthException):
            auth.close(revoke=True)
    assert auth.closed is True
Пример #8
0
def test_box_oauth_exception():
    status = 'status'
    message = 'message'
    url = 'https://example.com'
    method = 'GET'
    box_exception = BoxOAuthException(
        status,
        message=message,
        url=url,
        method=method,
    )
    assert str(box_exception) == '''
Message: {0}
Status: {1}
URL: {2}
Method: {3}'''.format(message, status, url, method)
Пример #9
0
def test_box_oauth_exception(has_network_response):
    status = 'status'
    message = 'message'
    url = 'https://example.com'
    method = 'GET'
    headers = {'header': 'value'}
    network_response = Mock(DefaultNetworkResponse,
                            headers=headers) if has_network_response else None
    box_exception = BoxOAuthException(
        status,
        message=message,
        url=url,
        method=method,
        network_response=network_response,
    )
    assert str(box_exception) == '''
Message: {0}
Status: {1}
URL: {2}
Method: {3}
Headers: {4}'''.format(message, status, url, method,
                       headers if has_network_response else 'N/A')
    assert box_exception.network_response is network_response
Пример #10
0
def test_revoke_on_close_can_be_skipped(client_id, client_secret, access_token,
                                        mock_box_session, close_args,
                                        close_kwargs):
    auth = OAuth2(client_id=client_id,
                  client_secret=client_secret,
                  access_token=access_token,
                  session=mock_box_session)
    with patch.object(auth, 'revoke') as mock_revoke:
        auth.close(*close_args, **close_kwargs)
    mock_revoke.assert_not_called()


@pytest.mark.parametrize(
    ('raise_from_block', 'raise_from_close', 'expected_exception'), [
        (MyError, None, MyError),
        (None, BoxOAuthException(status=500), BoxOAuthException),
        (MyError, BoxOAuthException(status=500), MyError),
    ])
@pytest.mark.parametrize(
    'close_kwargs',
    [{}, dict(revoke=False), dict(revoke=True)])
def test_context_manager_reraises_first_exception_after_close(
    client_id,
    client_secret,
    mock_box_session,
    close_kwargs,
    raise_from_block,
    raise_from_close,
    expected_exception,
):
    auth = OAuth2(client_id=client_id,
Пример #11
0
def box_auth(oauth):
    raise BoxOAuthException(status="Failed")