diff --git a/CHANGELOG.md b/CHANGELOG.md index c7f9a2f89..2a5a7cacb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `load_stac`/`metadata_from_stac`: add support for extracting actual temporal dimension metadata ([#567](https://github.com/Open-EO/openeo-python-client/issues/567)) - `MultiBackendJobManager`: add `cancel_running_job_after` option to automatically cancel jobs that are running for too long ([#590](https://github.com/Open-EO/openeo-python-client/issues/590)) - Added `openeo.api.process.Parameter` helper to easily create a "spatial_extent" UDP parameter +- Wrap OIDC token request failure in more descriptive `OidcException` (related to [#624](https://github.com/Open-EO/openeo-python-client/issues/624)) ### Changed diff --git a/openeo/rest/auth/oidc.py b/openeo/rest/auth/oidc.py index ac03d6e32..b7a79c80b 100644 --- a/openeo/rest/auth/oidc.py +++ b/openeo/rest/auth/oidc.py @@ -25,6 +25,7 @@ from typing import Callable, List, NamedTuple, Optional, Tuple, Union import requests +import requests.exceptions import openeo from openeo.internal.jupyter import in_jupyter_context @@ -402,7 +403,10 @@ def _do_token_post_request(self, post_data: dict) -> dict: g=self.grant_type, c=self.client_id, u=token_endpoint, p=list(post_data.keys()) ) ) - resp = self._requests.post(url=token_endpoint, data=post_data) + try: + resp = self._requests.post(url=token_endpoint, data=post_data) + except requests.exceptions.RequestException as e: + raise OidcException(f"Failed to retrieve access token at {token_endpoint!r}: {e!r}") from e if resp.status_code != 200: # TODO: are other status_code values valid too? raise OidcException( @@ -911,6 +915,7 @@ def get_tokens(self, request_refresh_token: bool = False) -> AccessTokenResult: f"Doing {self.grant_type!r} token request {token_endpoint!r} with post data fields {list(post_data.keys())!r} (client_id {self.client_id!r})" ) poll_ui.show_progress(status="Polling") + # TODO: skip occasional failing requests? (e.g. see `SkipIntermittentFailures` from openeo-aggregator) resp = self._requests.post(url=token_endpoint, data=post_data, timeout=5) if resp.status_code == 200: log.info(f"[{elapsed():5.1f}s] Authorized successfully.") diff --git a/tests/rest/auth/test_oidc.py b/tests/rest/auth/test_oidc.py index 3b3f1fbd7..98790fce2 100644 --- a/tests/rest/auth/test_oidc.py +++ b/tests/rest/auth/test_oidc.py @@ -324,6 +324,29 @@ def test_oidc_client_credentials_flow(requests_mock): assert oidc_mock.state["access_token"] == tokens.access_token +def test_oidc_client_credentials_flow_connection_error(requests_mock): + client_id = "myclient" + oidc_issuer = "https://oidc.test" + client_secret = "$3cr3t" + oidc_mock = OidcMock( + requests_mock=requests_mock, + expected_grant_type="client_credentials", + expected_client_id=client_id, + expected_fields={"client_secret": client_secret, "scope": "openid"}, + oidc_issuer=oidc_issuer, + ) + requests_mock.post(oidc_mock.token_endpoint, exc=requests.exceptions.ConnectionError) + + provider = OidcProviderInfo(issuer=oidc_issuer) + authenticator = OidcClientCredentialsAuthenticator( + client_info=OidcClientInfo(client_id=client_id, provider=provider, client_secret=client_secret) + ) + with pytest.raises( + OidcException, match="Failed to retrieve access token at 'https://oidc.test/token': ConnectionError" + ): + _ = authenticator.get_tokens() + + def test_oidc_resource_owner_password_credentials_flow(requests_mock): client_id = "myclient" client_secret = "$3cr3t"