mirror of
https://github.com/apache/superset.git
synced 2026-05-21 15:55:10 +00:00
Three independent bugs let MCP requests presenting Bearer tokens with the sst_ prefix authenticate as MCP_DEV_USERNAME without any validation under streamable-http: 1. _resolve_user_from_api_key read the token from flask.request.headers, but the streamable-http transport never pushes a Flask request context — has_request_context() was always False, so the function returned None before validating, falling through to the dev-user fallback. Now reads the token from FastMCP's per-request AccessToken (which the CompositeTokenVerifier already populated) and fails closed when the key is invalid. 2. CompositeTokenVerifier was only installed when MCP_AUTH_ENABLED=True. With FAB_API_KEY_ENABLED=True alone, no transport-level verifier existed at all. The factory now builds an API-key-only verifier in that case (jwt_verifier=None) that rejects non-API-key Bearer tokens at the transport instead of silently accepting them. 3. The pass-through AccessToken was minted with scopes=[], which would make FastMCP's RequireAuthMiddleware 403 every API-key request when MCP_REQUIRED_SCOPES is non-empty. Pass-through now propagates self.required_scopes. Also addresses Daniel's review comment on superset/security/manager.py: adds "ApiKey" to ADMIN_ONLY_VIEW_MENUS so the FAB ApiKeyApi PVMs are gated to Admin instead of leaking to Alpha and Gamma. Renames the pass-through claim from _api_key_passthrough to the namespaced _superset_mcp_api_key_passthrough (exported as API_KEY_PASSTHROUGH_CLAIM) so a custom claim from an external IdP can't accidentally divert a JWT into the API-key validation path. Tests updated to mock get_access_token instead of app.test_request_context (the simulated Flask context was the reason the prior tests passed while production failed). New tests cover API-key-only verifier mode, scope propagation on pass-through, and the namespaced-claim isolation.