mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-11-06 13:12:27 +01:00
fix(auth): require owner for cached provider credentials
This commit is contained in:
@@ -258,6 +258,16 @@ def resolve_runtime_credentials(
|
|||||||
force_refresh: bool = False,
|
force_refresh: bool = False,
|
||||||
allow_live_probes: bool = True,
|
allow_live_probes: bool = True,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
|
normalized_owner = None
|
||||||
|
if not allow_live_probes:
|
||||||
|
from src.owner_identity import is_request_sentinel_owner, normalize_owner
|
||||||
|
|
||||||
|
normalized_owner = normalize_owner(owner)
|
||||||
|
if normalized_owner is None or is_request_sentinel_owner(normalized_owner):
|
||||||
|
raise ChatGPTSubscriptionAuthNotFound(
|
||||||
|
"ChatGPT Subscription credentials require an authenticated owner."
|
||||||
|
)
|
||||||
|
|
||||||
ProviderAuthSession, SessionLocal, utcnow_naive = _database_handles()
|
ProviderAuthSession, SessionLocal, utcnow_naive = _database_handles()
|
||||||
db = SessionLocal()
|
db = SessionLocal()
|
||||||
try:
|
try:
|
||||||
@@ -265,7 +275,9 @@ def resolve_runtime_credentials(
|
|||||||
ProviderAuthSession.id == auth_id,
|
ProviderAuthSession.id == auth_id,
|
||||||
ProviderAuthSession.provider == CHATGPT_SUBSCRIPTION_PROVIDER,
|
ProviderAuthSession.provider == CHATGPT_SUBSCRIPTION_PROVIDER,
|
||||||
)
|
)
|
||||||
if owner:
|
if not allow_live_probes:
|
||||||
|
q = q.filter(ProviderAuthSession.owner == normalized_owner)
|
||||||
|
elif owner:
|
||||||
q = q.filter(ProviderAuthSession.owner == owner)
|
q = q.filter(ProviderAuthSession.owner == owner)
|
||||||
row = q.first()
|
row = q.first()
|
||||||
if row is None:
|
if row is None:
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
"""Cycle-8 regressions for bearer provider-auth session repair."""
|
"""Cycle-8/9 regressions for bearer provider-auth session repair."""
|
||||||
|
|
||||||
|
import base64
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -14,7 +16,16 @@ import core.database as cdb
|
|||||||
_CODEX_BASE = "https://chatgpt.com/backend-api/codex"
|
_CODEX_BASE = "https://chatgpt.com/backend-api/codex"
|
||||||
|
|
||||||
|
|
||||||
def _provider_db(monkeypatch):
|
def _future_access_token():
|
||||||
|
def encode(payload):
|
||||||
|
return base64.urlsafe_b64encode(
|
||||||
|
json.dumps(payload, separators=(",", ":")).encode()
|
||||||
|
).rstrip(b"=").decode()
|
||||||
|
|
||||||
|
return f"{encode({'alg': 'none'})}.{encode({'exp': int(time.time()) + 3600})}.signature"
|
||||||
|
|
||||||
|
|
||||||
|
def _provider_db(monkeypatch, *, access_token="cached-access-token"):
|
||||||
from routes import chat_helpers
|
from routes import chat_helpers
|
||||||
from src import chatgpt_subscription
|
from src import chatgpt_subscription
|
||||||
|
|
||||||
@@ -34,7 +45,7 @@ def _provider_db(monkeypatch):
|
|||||||
provider="chatgpt-subscription",
|
provider="chatgpt-subscription",
|
||||||
owner="alice",
|
owner="alice",
|
||||||
base_url=_CODEX_BASE,
|
base_url=_CODEX_BASE,
|
||||||
access_token="cached-access-token",
|
access_token=access_token,
|
||||||
refresh_token="refresh-token",
|
refresh_token="refresh-token",
|
||||||
auth_mode="chatgpt",
|
auth_mode="chatgpt",
|
||||||
))
|
))
|
||||||
@@ -92,3 +103,58 @@ def test_bearer_validator_rejects_provider_auth_when_cache_is_unusable(monkeypat
|
|||||||
with pytest.raises(HTTPException) as exc:
|
with pytest.raises(HTTPException) as exc:
|
||||||
_validate_bearer_session_model(_registered_session(), owner="alice")
|
_validate_bearer_session_model(_registered_session(), owner="alice")
|
||||||
assert exc.value.status_code == 401
|
assert exc.value.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"owner",
|
||||||
|
[None, "", " ", "api", "demo", "system", "internal-tool", " API "],
|
||||||
|
)
|
||||||
|
def test_cache_only_provider_auth_rejects_missing_and_sentinel_owners_before_query(monkeypatch, owner):
|
||||||
|
from src import chatgpt_subscription
|
||||||
|
|
||||||
|
def forbidden_database_handles():
|
||||||
|
pytest.fail("cache-only provider auth queried without a real owner")
|
||||||
|
|
||||||
|
monkeypatch.setattr(chatgpt_subscription, "_database_handles", forbidden_database_handles)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
chatgpt_subscription,
|
||||||
|
"refresh_oauth_tokens",
|
||||||
|
lambda *args, **kwargs: pytest.fail("cache-only provider auth refreshed credentials"),
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(chatgpt_subscription.ChatGPTSubscriptionAuthNotFound):
|
||||||
|
chatgpt_subscription.resolve_runtime_credentials(
|
||||||
|
"auth-1", owner=owner, allow_live_probes=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cache_only_provider_auth_normalizes_exact_owner_and_blocks_live_io(monkeypatch):
|
||||||
|
from src import chatgpt_subscription
|
||||||
|
|
||||||
|
access_token = _future_access_token()
|
||||||
|
_provider_db(monkeypatch, access_token=access_token)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
chatgpt_subscription,
|
||||||
|
"refresh_oauth_tokens",
|
||||||
|
lambda *args, **kwargs: pytest.fail("cache-only provider auth refreshed credentials"),
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
chatgpt_subscription.httpx,
|
||||||
|
"get",
|
||||||
|
lambda *args, **kwargs: pytest.fail("cache-only provider auth probed the provider"),
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
chatgpt_subscription.httpx,
|
||||||
|
"post",
|
||||||
|
lambda *args, **kwargs: pytest.fail("cache-only provider auth probed the provider"),
|
||||||
|
)
|
||||||
|
|
||||||
|
result = chatgpt_subscription.resolve_runtime_credentials(
|
||||||
|
"auth-1", owner=" alice ", allow_live_probes=False
|
||||||
|
)
|
||||||
|
assert result["api_key"] == access_token
|
||||||
|
|
||||||
|
with pytest.raises(chatgpt_subscription.ChatGPTSubscriptionAuthNotFound):
|
||||||
|
chatgpt_subscription.resolve_runtime_credentials(
|
||||||
|
"auth-1", owner="bob", allow_live_probes=False
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user