Skip to content

Commit 15e7246

Browse files
committed
fixup! fixup! fixup! MultiBackendJobManager: refresh bearer before _JobStartTask #817
1 parent fbf0fb0 commit 15e7246

File tree

2 files changed

+97
-27
lines changed

2 files changed

+97
-27
lines changed

openeo/rest/auth/testing.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ def token_callback_resource_owner_password_credentials(self, params: dict, conte
143143
assert params["scope"] == self.expected_fields["scope"]
144144
return self._build_token_response()
145145

146+
def token_callback_block_400(self, params: dict, context):
147+
"""Failing callback with 400 Bad Request"""
148+
context.status_code = 400
149+
return "block_400"
150+
146151
def device_code_callback(self, request: requests_mock.request._RequestObjectProxy, context):
147152
params = self._get_query_params(query=request.text)
148153
assert params["client_id"] == self.expected_client_id

tests/rest/test_connection.py

Lines changed: 92 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,30 +2365,31 @@ def test_authenticate_oidc_auto_renew_expired_access_token_initial_client_creden
23652365
requests_mock.get(API_URL, json={"api_version": "1.0.0"})
23662366
client_id = "myclient"
23672367
client_secret = "$3cr3t"
2368-
issuer = "https://oidc.test"
2368+
oidc_issuer = "https://oidc.test"
23692369
requests_mock.get(
23702370
API_URL + "credentials/oidc",
2371-
json={"providers": [{"id": "oi", "issuer": issuer, "title": "example", "scopes": ["openid"]}]},
2371+
json={"providers": [{"id": "oi", "issuer": oidc_issuer, "title": "example", "scopes": ["openid"]}]},
23722372
)
23732373
oidc_mock = OidcMock(
23742374
requests_mock=requests_mock,
23752375
expected_grant_type="client_credentials",
23762376
expected_client_id=client_id,
23772377
expected_fields={"client_secret": client_secret, "scope": "openid"},
2378-
oidc_issuer=issuer,
2378+
oidc_issuer=oidc_issuer,
23792379
)
23802380

23812381
_setup_get_me_handler(
23822382
requests_mock=requests_mock, oidc_mock=oidc_mock, token_invalid_status_code=token_invalid_status_code
23832383
)
23842384
caplog.set_level(logging.INFO)
23852385

2386-
# Explicit authentication with `authenticate_oidc_refresh_token`
2386+
# Initial authentication with `authenticate_oidc_client_credentials`
23872387
conn = Connection(API_URL, refresh_token_store=refresh_token_store)
23882388
assert isinstance(conn.auth, NullAuth)
23892389
conn.authenticate_oidc_client_credentials(client_id=client_id, client_secret=client_secret)
23902390
assert isinstance(conn.auth, BearerAuth)
23912391
assert conn.auth.bearer == "oidc/oi/" + oidc_mock.state["access_token"]
2392+
23922393
# Just one "client_credentials" auth request so far
23932394
assert [h["grant_type"] for h in oidc_mock.grant_request_history] == ["client_credentials"]
23942395
access_token1 = oidc_mock.state["access_token"]
@@ -2460,7 +2461,7 @@ def test_authenticate_oidc_auto_renew_expired_access_token_initial_client_creden
24602461
)
24612462
caplog.set_level(logging.INFO)
24622463

2463-
# Explicit authentication with `authenticate_oidc_refresh_token`
2464+
# Initial authentication with `authenticate_oidc_client_credentials`
24642465
conn = Connection(API_URL, refresh_token_store=refresh_token_store)
24652466
assert isinstance(conn.auth, NullAuth)
24662467
conn.authenticate_oidc_client_credentials(client_id=client_id, client_secret=client_secret)
@@ -2477,9 +2478,9 @@ def test_authenticate_oidc_auto_renew_expired_access_token_initial_client_creden
24772478
"_used_access_token": access_token1,
24782479
}
24792480

2480-
# Expire access token don't accept client credentials anymore
2481+
# Expire access token, and don't accept client credentials anymore
24812482
oidc_mock.invalidate_access_token()
2482-
requests_mock.post(oidc_mock.token_endpoint, status_code=401, text="nope")
2483+
oidc_mock.token_callback_client_credentials = oidc_mock.token_callback_block_400
24832484
# Do request that requires auth headers and might trigger re-authentication
24842485
assert f"{token_invalid_status_code} TokenInvalid" not in caplog.text
24852486
with pytest.raises(
@@ -2508,16 +2509,7 @@ def test_try_access_token_refresh_initial_refresh_token(
25082509
oidc_issuer = "https://oidc.test"
25092510
requests_mock.get(
25102511
API_URL + "credentials/oidc",
2511-
json={
2512-
"providers": [
2513-
{
2514-
"id": "oi",
2515-
"issuer": oidc_issuer,
2516-
"title": "example",
2517-
"scopes": ["openid"],
2518-
}
2519-
]
2520-
},
2512+
json={"providers": [{"id": "oi", "issuer": oidc_issuer, "title": "example", "scopes": ["openid"]}]},
25212513
)
25222514
oidc_mock = OidcMock(
25232515
requests_mock=requests_mock,
@@ -2593,16 +2585,7 @@ def test_try_access_token_refresh_initial_device_code(
25932585
oidc_issuer = "https://oidc.test"
25942586
requests_mock.get(
25952587
API_URL + "credentials/oidc",
2596-
json={
2597-
"providers": [
2598-
{
2599-
"id": "oi",
2600-
"issuer": oidc_issuer,
2601-
"title": "example",
2602-
"scopes": ["openid"],
2603-
}
2604-
]
2605-
},
2588+
json={"providers": [{"id": "oi", "issuer": oidc_issuer, "title": "example", "scopes": ["openid"]}]},
26062589
)
26072590
oidc_mock = OidcMock(
26082591
requests_mock=requests_mock,
@@ -2680,6 +2663,88 @@ def test_try_access_token_refresh_initial_device_code(
26802663
}
26812664

26822665

2666+
@pytest.mark.parametrize(
2667+
["block_token_endpoint", "expect_refresh"],
2668+
[
2669+
(False, True),
2670+
(True, False),
2671+
],
2672+
)
2673+
def test_try_access_token_refresh_initial_client_credentials(
2674+
requests_mock, refresh_token_store, caplog, block_token_endpoint, expect_refresh, oidc_device_code_flow_checker
2675+
):
2676+
requests_mock.get(API_URL, json={"api_version": "1.0.0"})
2677+
client_id = "myclient"
2678+
client_secret = "$3cr3t"
2679+
oidc_issuer = "https://oidc.test"
2680+
requests_mock.get(
2681+
API_URL + "credentials/oidc",
2682+
json={"providers": [{"id": "oi", "issuer": oidc_issuer, "title": "example", "scopes": ["openid"]}]},
2683+
)
2684+
oidc_mock = OidcMock(
2685+
requests_mock=requests_mock,
2686+
expected_grant_type="client_credentials",
2687+
expected_client_id=client_id,
2688+
expected_fields={"client_secret": client_secret, "scope": "openid"},
2689+
oidc_issuer=oidc_issuer,
2690+
)
2691+
_setup_get_me_handler(requests_mock=requests_mock, oidc_mock=oidc_mock)
2692+
caplog.set_level(logging.WARNING)
2693+
2694+
# Initial authentication with `authenticate_oidc_client_credentials`
2695+
conn = Connection(API_URL, refresh_token_store=refresh_token_store)
2696+
assert isinstance(conn.auth, NullAuth)
2697+
conn.authenticate_oidc_client_credentials(client_id=client_id, client_secret=client_secret)
2698+
assert isinstance(conn.auth, BearerAuth) and conn.auth.bearer == "oidc/oi/" + oidc_mock.state["access_token"]
2699+
2700+
# Just one "refresh_token" auth request so far
2701+
assert [h["grant_type"] for h in oidc_mock.grant_request_history] == [
2702+
"client_credentials",
2703+
]
2704+
access_token1 = oidc_mock.state["access_token"]
2705+
2706+
# Do request that requires auth headers
2707+
assert conn.describe_account() == {
2708+
"user_id": "john",
2709+
"_used_oidc_provider": "oi",
2710+
"_used_access_token": access_token1,
2711+
}
2712+
2713+
# Prepare for refresh attempt
2714+
if block_token_endpoint:
2715+
oidc_mock.token_callback_client_credentials = oidc_mock.token_callback_block_400
2716+
2717+
# Trigger refresh
2718+
refreshed = conn.try_access_token_refresh(reason="Can I Haz Fresh")
2719+
2720+
# Two "refresh_token" auth request attempts should have happened now
2721+
assert [h["grant_type"] for h in oidc_mock.grant_request_history] == [
2722+
"client_credentials",
2723+
"client_credentials",
2724+
]
2725+
access_token2 = oidc_mock.state["access_token"]
2726+
2727+
if expect_refresh:
2728+
assert refreshed == True
2729+
assert access_token2 != access_token1
2730+
assert caplog.messages == []
2731+
else:
2732+
assert refreshed == False
2733+
assert access_token2 == access_token1
2734+
assert caplog.messages == [
2735+
dirty_equals.IsStr(
2736+
regex="Failed to obtain new access token.*grant 'client_credentials'.*block_400.*Reason: Can I Haz Fresh"
2737+
)
2738+
]
2739+
2740+
# New request with fresh token?
2741+
assert conn.describe_account() == {
2742+
"user_id": "john",
2743+
"_used_oidc_provider": "oi",
2744+
"_used_access_token": access_token2,
2745+
}
2746+
2747+
26832748
class TestAuthenticateOidcAccessToken:
26842749
@pytest.fixture(autouse=True)
26852750
def _setup(self, requests_mock):

0 commit comments

Comments
 (0)