Skip to content

Commit 1f09036

Browse files
MatthewJamisonJSbenoit-cty
authored andcommitted
test: cover joserfc migration paths (#1197)
Address review follow-ups on the authlib.jose -> joserfc migration: - tests/cli/test_cli_auth.py: strengthen test_validate_access_token_valid with a realistic claims dict (exp/iat/sub) so JWTClaimsRegistry actually exercises its default validators instead of trivially passing on an empty payload. Add test_validate_access_token_expired_returns_false to pin down the expiry-rejection behaviour through the real registry. - carbonserver/tests/api/service/test_auth_provider.py: add test_decode_token_falls_back_to_jwks_when_fief_fails covering the previously-untested JWKS fallback in OIDCAuthProvider._decode_token — the only joserfc-using path in carbonserver.
1 parent 93514cb commit 1f09036

2 files changed

Lines changed: 79 additions & 1 deletion

File tree

carbonserver/tests/api/service/test_auth_provider.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
Unit tests for OIDC authentication provider.
33
"""
44

5+
import time
6+
from unittest.mock import AsyncMock, MagicMock, patch
7+
8+
import pytest
9+
10+
from carbonserver.api.services.auth_providers import oidc_auth_provider
511
from carbonserver.api.services.auth_providers.oidc_auth_provider import OIDCAuthProvider
612
from carbonserver.config import settings
713

@@ -26,3 +32,52 @@ def test_oidc_provider_initialization(self):
2632
settings.oidc_client_id,
2733
settings.oidc_client_secret,
2834
)
35+
36+
@pytest.mark.asyncio
37+
async def test_decode_token_falls_back_to_jwks_when_fief_fails(self):
38+
"""When fief.validate_access_token raises, _decode_token must fall back
39+
to the joserfc JWKS verification path and return a plain dict."""
40+
provider = OIDCAuthProvider(
41+
base_url="https://auth.example.com",
42+
client_id="test_client",
43+
client_secret="test_secret",
44+
)
45+
46+
now = int(time.time())
47+
expected_claims = {
48+
"sub": "user-456",
49+
"iat": now - 5,
50+
"exp": now + 600,
51+
"email": "user@example.com",
52+
}
53+
54+
jwks_payload = {"keys": [{"kty": "RSA", "kid": "k1"}]}
55+
provider.client = MagicMock()
56+
provider.client.fetch_jwk_set = AsyncMock(return_value=jwks_payload)
57+
58+
decoded_token = MagicMock()
59+
decoded_token.claims = expected_claims
60+
61+
with (
62+
patch.object(
63+
oidc_auth_provider.fief,
64+
"validate_access_token",
65+
new=AsyncMock(side_effect=Exception("fief unavailable")),
66+
),
67+
patch.object(
68+
oidc_auth_provider.KeySet,
69+
"import_key_set",
70+
return_value="keyset",
71+
) as mock_import,
72+
patch.object(
73+
oidc_auth_provider.jose_jwt,
74+
"decode",
75+
return_value=decoded_token,
76+
) as mock_decode,
77+
):
78+
result = await provider._decode_token("opaque-token")
79+
80+
assert result == expected_claims
81+
assert isinstance(result, dict)
82+
mock_import.assert_called_once_with(jwks_payload)
83+
mock_decode.assert_called_once_with("opaque-token", "keyset")

tests/cli/test_cli_auth.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import io
22
import json
33
import tempfile
4+
import time
45
import unittest
56
from pathlib import Path
67
from unittest.mock import MagicMock, patch
@@ -98,12 +99,34 @@ def test_validate_access_token_valid(
9899
mock_get.return_value.json.return_value = {"jwks_uri": "jwks"}
99100
mock_get.return_value.raise_for_status.return_value = None
100101
mock_import_key_set.return_value = "keyset"
101-
mock_decode.return_value.claims = {}
102+
now = int(time.time())
103+
mock_decode.return_value.claims = {
104+
"iat": now - 10,
105+
"exp": now + 300,
106+
"sub": "user-123",
107+
}
102108
with patch(
103109
"codecarbon.cli.auth._discover_endpoints", return_value={"jwks_uri": "jwks"}
104110
):
105111
self.assertTrue(auth._validate_access_token("token"))
106112

113+
@patch("codecarbon.cli.auth.requests.get")
114+
@patch("codecarbon.cli.auth.KeySet.import_key_set")
115+
@patch("codecarbon.cli.auth.jose_jwt.decode")
116+
def test_validate_access_token_expired_returns_false(
117+
self, mock_decode, mock_import_key_set, mock_get
118+
):
119+
# Expired exp must trip JWTClaimsRegistry validation
120+
mock_get.return_value.json.return_value = {"jwks_uri": "jwks"}
121+
mock_get.return_value.raise_for_status.return_value = None
122+
mock_import_key_set.return_value = "keyset"
123+
now = int(time.time())
124+
mock_decode.return_value.claims = {"exp": now - 10}
125+
with patch(
126+
"codecarbon.cli.auth._discover_endpoints", return_value={"jwks_uri": "jwks"}
127+
):
128+
self.assertFalse(auth._validate_access_token("token"))
129+
107130
@patch("codecarbon.cli.auth._discover_endpoints", return_value={"jwks_uri": "jwks"})
108131
@patch(
109132
"codecarbon.cli.auth.requests.get",

0 commit comments

Comments
 (0)