fix(auth): address PR #758 auto-review (id-token verify, nonce, CI key)
Blocking: - AS proxy callback now calls verify_id_token before caching the proxy code so a tampered IdP response can't smuggle identity claims. Important: - Browser OAuth flow generates and verifies an OIDC nonce; new alembic migration 006 adds the nonce column to oauth_sessions. - _origin_matches_self logs a warning when CSRF check is bypassed. - oauth_tools.py uses get_shared_storage instead of fresh handles. Nits: - New token_utils.get_oidc_discovery shares the 5-minute cache with verify_id_token; oauth_login (integrated) and _revoke_refresh_token_at_idp now use it instead of issuing fresh discovery fetches. - Drop typing.Optional from oauth_tools.py in favour of X | None. CI: - test.yml generates an ephemeral Fernet TOKEN_ENCRYPTION_KEY per run with openssl, removing the dependency on a missing repo secret. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
2ef4bfc4af
commit
4c84d82984
@@ -20,6 +20,7 @@ import pytest
|
||||
from cryptography.fernet import Fernet
|
||||
from starlette.requests import HTTPConnection
|
||||
|
||||
from nextcloud_mcp_server.auth import token_utils
|
||||
from nextcloud_mcp_server.auth.browser_oauth_routes import (
|
||||
_revoke_refresh_token_at_idp,
|
||||
oauth_logout,
|
||||
@@ -30,6 +31,20 @@ from nextcloud_mcp_server.auth.storage import RefreshTokenStorage
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clear_oidc_discovery_cache():
|
||||
"""Reset the shared discovery cache so tests don't see each other's fetches.
|
||||
|
||||
``_revoke_refresh_token_at_idp`` was changed (PR #758 nit 6) to use
|
||||
``token_utils.get_oidc_discovery`` which caches for 5 minutes — without
|
||||
this clear, the second test in the file would see the first test's
|
||||
discovery doc and skip the MockTransport call.
|
||||
"""
|
||||
token_utils._discovery_cache.clear()
|
||||
yield
|
||||
token_utils._discovery_cache.clear()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# storage fixture (real SQLite backend; lighter than mocking every call)
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -337,9 +352,17 @@ async def test_revoke_helper_posts_to_revocation_endpoint():
|
||||
kwargs["transport"] = transport
|
||||
return httpx.AsyncClient(**kwargs)
|
||||
|
||||
with patch(
|
||||
"nextcloud_mcp_server.auth.browser_oauth_routes.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
# Discovery now goes through token_utils.get_oidc_discovery (PR #758 nit
|
||||
# 6); revocation POST still uses browser_oauth_routes' httpx client.
|
||||
with (
|
||||
patch(
|
||||
"nextcloud_mcp_server.auth.browser_oauth_routes.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
),
|
||||
patch(
|
||||
"nextcloud_mcp_server.auth.token_utils.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
),
|
||||
):
|
||||
await _revoke_refresh_token_at_idp(
|
||||
{
|
||||
@@ -373,9 +396,15 @@ async def test_revoke_helper_skips_when_no_revocation_endpoint():
|
||||
kwargs["transport"] = transport
|
||||
return httpx.AsyncClient(**kwargs)
|
||||
|
||||
with patch(
|
||||
"nextcloud_mcp_server.auth.browser_oauth_routes.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
with (
|
||||
patch(
|
||||
"nextcloud_mcp_server.auth.browser_oauth_routes.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
),
|
||||
patch(
|
||||
"nextcloud_mcp_server.auth.token_utils.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
),
|
||||
):
|
||||
# Returns None and does not raise
|
||||
result = await _revoke_refresh_token_at_idp(
|
||||
@@ -403,9 +432,15 @@ async def test_revoke_helper_silent_on_idp_error():
|
||||
kwargs["transport"] = transport
|
||||
return httpx.AsyncClient(**kwargs)
|
||||
|
||||
with patch(
|
||||
"nextcloud_mcp_server.auth.browser_oauth_routes.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
with (
|
||||
patch(
|
||||
"nextcloud_mcp_server.auth.browser_oauth_routes.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
),
|
||||
patch(
|
||||
"nextcloud_mcp_server.auth.token_utils.nextcloud_httpx_client",
|
||||
side_effect=fake_client,
|
||||
),
|
||||
):
|
||||
result = await _revoke_refresh_token_at_idp(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user