ashb commented on code in PR #68054:
URL: https://github.com/apache/airflow/pull/68054#discussion_r3380660675
##########
airflow-core/src/airflow/api_fastapi/execution_api/app.py:
##########
@@ -135,25 +136,22 @@ async def dispatch(self, request: Request, call_next):
response: Response = await call_next(request)
refreshed_token: str | None = None
- auth_header = request.headers.get("authorization")
- if auth_header and auth_header.lower().startswith("bearer "):
- token = auth_header.split(" ", 1)[1]
+ token = request.scope.get(_REQUEST_SCOPE_TOKEN_KEY)
+ if token:
try:
- async with svcs.Container(request.app.state.svcs_registry) as
services:
- validator: JWTValidator = await services.aget(JWTValidator)
- claims = await validator.avalidated_claims(token, {})
-
- # Workload tokens are long-lived and meant to survive queue
- # wait times so avoid refreshing them. If avalidated_claims
- # raises for a workload token, the outer except handles it.
- if claims.get("scope") == "workload":
- return response
-
- now = int(time.time())
- token_lifetime = int(claims.get("exp", 0)) -
int(claims.get("iat", 0))
- refresh_when_less_than = max(int(token_lifetime * 0.20),
30)
- valid_left = int(claims.get("exp", 0)) - now
- if valid_left <= refresh_when_less_than:
+ claims = {"sub": str(token.id), **token.claims.model_dump()}
Review Comment:
What uses the `sub` claim? It looks unused.
##########
airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_router.py:
##########
@@ -67,3 +126,41 @@ def test_expiring_token_is_reissued(
assert "Refreshed-API-Token" in response.headers
else:
assert "Refreshed-API-Token" not in response.headers
+ # avalidated_claims must be called exactly once — by JWTBearer only, not
by the middleware.
+ auth.avalidated_claims.assert_awaited_once_with("dummy", {})
+
+
[email protected]_test
+def test_token_expiring_mid_request_is_reissued_without_revalidation(client,
exec_app: FastAPI, time_machine):
+ """Middleware reissues from cached JWTBearer claims without re-validating
the token.
+
+ Regression test for the TOCTOU race in JWTReissueMiddleware: a heartbeat
arrives with a
+ token that has ~0s left, JWTBearer validates it (still technically valid
at that moment),
+ the request completes, and the middleware runs. In the old code the
middleware would call
Review Comment:
```suggestion
the request starts, and the middleware runs. In the old code the
middleware would call
```
I think?
##########
airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_router.py:
##########
@@ -20,17 +20,76 @@
from unittest.mock import AsyncMock
import pytest
-from fastapi import FastAPI
+import svcs
+from fastapi import FastAPI, HTTPException, Request, status
+from fastapi.security import HTTPBearer
+from fastapi.testclient import TestClient
from airflow.api_fastapi.auth.tokens import JWTValidator
from airflow.api_fastapi.execution_api.app import lifespan
+from airflow.api_fastapi.execution_api.datamodels.token import TIClaims,
TIToken
+from airflow.api_fastapi.execution_api.security import (
+ _REQUEST_SCOPE_TOKEN_KEY,
+ _jwt_bearer,
+)
+
+
[email protected]
+def client():
Review Comment:
This has a very generic fixture name, `client`, but it does stuff very
specific to testing jwt bearer. It likely shouldn't be a module fixture, or
should have a less generic name.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]