eager-auth 2.2.0__tar.gz → 2.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {eager_auth-2.2.0 → eager_auth-2.2.1}/PKG-INFO +2 -2
- {eager_auth-2.2.0 → eager_auth-2.2.1}/pyproject.toml +4 -2
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/tokens.py +3 -1
- eager_auth-2.2.1/tests/test_hostile_tokens.py +30 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/.gitignore +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/LICENSE +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/README.md +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/__init__.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/claims.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/config.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/context.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/discovery.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/errors.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/fastapi.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/flow.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/keys.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/pending.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/presets.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/principal.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/src/eager_auth/session.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/conftest.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_callback.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_config.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_conformance.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_fastapi.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_flow.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_http_jwks_source.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_keys.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_lifecycle.py +0 -0
- {eager_auth-2.2.0 → eager_auth-2.2.1}/tests/test_session.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: eager-auth
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: Standard OIDC relying party for Eager FastAPI services — verification core
|
|
5
5
|
Project-URL: Homepage, https://github.com/Whats-Next-CC/eager-auth
|
|
6
6
|
Project-URL: Source, https://github.com/Whats-Next-CC/eager-auth
|
|
@@ -20,7 +20,7 @@ Classifier: Typing :: Typed
|
|
|
20
20
|
Requires-Python: >=3.12
|
|
21
21
|
Requires-Dist: httpx>=0.27
|
|
22
22
|
Requires-Dist: joserfc>=1.0
|
|
23
|
-
Requires-Dist: pyjwt[crypto]>=2.
|
|
23
|
+
Requires-Dist: pyjwt[crypto]>=2.15.0
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: black>=24.0; extra == 'dev'
|
|
26
26
|
Requires-Dist: fastapi>=0.110; extra == 'dev'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "eager-auth"
|
|
3
|
-
version = "2.2.
|
|
3
|
+
version = "2.2.1"
|
|
4
4
|
description = "Standard OIDC relying party for Eager FastAPI services — verification core"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -20,7 +20,9 @@ classifiers = [
|
|
|
20
20
|
license = "Apache-2.0"
|
|
21
21
|
license-files = ["LICENSE"]
|
|
22
22
|
dependencies = [
|
|
23
|
-
|
|
23
|
+
# 2.15.0 is the first release with no open advisory: of the thirteen published on
|
|
24
|
+
# 2026-09-29/30, 2.14.0 fixed twelve and GHSA-42vr-xj54-vc7v still affects 2.14.0.
|
|
25
|
+
"pyjwt[crypto]>=2.15.0",
|
|
24
26
|
"httpx>=0.27",
|
|
25
27
|
"joserfc>=1.0",
|
|
26
28
|
]
|
|
@@ -74,7 +74,9 @@ def _header_algorithm(token: str, config: AuthConfig) -> str:
|
|
|
74
74
|
"""Read `alg` from the header and refuse anything symmetric, before touching keys."""
|
|
75
75
|
try:
|
|
76
76
|
header = jwt.get_unverified_header(token)
|
|
77
|
-
|
|
77
|
+
# RecursionError: a deeply nested header is attacker input read before any signature
|
|
78
|
+
# check, and PyJWT has let json.loads raise it unwrapped (GHSA-8wjv-2p76-3863).
|
|
79
|
+
except (jwt.InvalidTokenError, RecursionError) as exc:
|
|
78
80
|
raise MalformedTokenError(f"cannot read token header: {exc}") from exc
|
|
79
81
|
|
|
80
82
|
algorithm = header.get("alg")
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Tokens built to crash the parser rather than to forge a principal.
|
|
2
|
+
|
|
3
|
+
The header is read before any signature check, so whatever it contains comes from an
|
|
4
|
+
unauthenticated caller. Every such token must end as a typed InvalidTokenError (a 401),
|
|
5
|
+
never as an exception the framework turns into a 500.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import base64
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from eager_auth import MalformedTokenError, verify_id_token
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _b64(raw: bytes) -> str:
|
|
16
|
+
return base64.urlsafe_b64encode(raw).rstrip(b"=").decode()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _token_with_header(header: bytes) -> str:
|
|
20
|
+
return f"{_b64(header)}.{_b64(b'{}')}.{_b64(b'signature')}"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.parametrize("depth", [10_000, 100_000])
|
|
24
|
+
def test_deeply_nested_header_is_malformed_not_a_crash(depth, config, resolver):
|
|
25
|
+
# GHSA-8wjv-2p76-3863: PyJWT 2.13.0 lets json.loads raise RecursionError here, which
|
|
26
|
+
# is a RuntimeError, not an InvalidTokenError.
|
|
27
|
+
header = b'{"alg":"RS256","x":' + b"[" * depth + b"]" * depth + b"}"
|
|
28
|
+
|
|
29
|
+
with pytest.raises(MalformedTokenError):
|
|
30
|
+
verify_id_token(_token_with_header(header), config=config, keys=resolver)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|