Commit Graph

2734 Commits

Author SHA1 Message Date
Amin Ghadersohi
d8db1c9230 refactor(mcp): delegate load_user_with_relationships to SecurityManager.find_user_with_relationships
Fixes a gap identified in code review: the standalone load_user_with_relationships()
in auth.py duplicated SecurityManager.find_user() logic but dropped two FAB behaviors:
- auth_username_ci (case-insensitive username lookup)
- MultipleResultsFound guard (username uniqueness not guaranteed at DB level in all FAB versions)
It also hard-coded User/Group models instead of sm.user_model.

Changes:
- Add SupersetSecurityManager.find_user_with_relationships() to security/manager.py,
  mirroring FAB's find_user() (auth_username_ci, MultipleResultsFound handling,
  self.user_model) and adding eager loading of roles and group.roles via joinedload
- Simplify load_user_with_relationships() in auth.py to a thin delegate to the
  new method, removing the duplicated query logic and raw Group/User imports
- Add regression test asserting find_user_with_relationships() exists on the SM

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 22:10:36 +00:00
Amin Ghadersohi
202b19951a fix(mcp): harden auth — PermissionError propagation, passthrough client_id guard, fail-closed on missing token
- _tool_allowed_for_current_user (server.py): catch PermissionError
  alongside ValueError so invalid API keys return False instead of
  propagating through the tool-search permission filter
- _setup_user_context (auth.py): catch PermissionError alongside
  ValueError so g.user is cleared and the error is logged consistently
  regardless of which failure type get_user_from_request() raises
- _resolve_user_from_api_key (auth.py): require client_id=="api_key"
  (set by CompositeTokenVerifier) in addition to API_KEY_PASSTHROUGH_CLAIM
  to prevent an external IdP JWT that happens to include the claim name
  from being misclassified as an API-key pass-through (DoS vector)
- _resolve_user_from_jwt_context (auth.py): same client_id guard so
  a rogue-claim JWT continues through JWT resolution instead of deferring
  to the API-key path (which would raise PermissionError for the user)
- _resolve_user_from_api_key (auth.py): raise PermissionError (not
  return None) when the pass-through claim is present but the raw token
  is absent — fail closed rather than falling through to weaker auth
- Tests: set client_id="api_key" on _passthrough_access_token helper;
  update test_jwt_context_with_api_key_passthrough_returns_none docstring;
  add test for namespaced claim on non-API-key client_id being ignored

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:26:42 +00:00
Amin Ghadersohi
d675a97686 refactor(mcp): extract duplicated app context + sm setup into helper
Add _mock_sm_ctx() context manager to eliminate repeated boilerplate
(g.user = None / app.appbuilder = MagicMock() / appbuilder.sm = mock_sm)
across seven API key auth unit tests.
2026-05-13 19:57:41 +00:00
Amin Ghadersohi
ba97a29468 fix(mcp): fix stale patch target in auth tests and update stale docstring
- Use superset.mcp_service.auth.has_request_context as patch target in
  test_mcp_auth_hook_clears_stale_g_user tests; patching flask.has_request_context
  has no effect on the module-level import already bound in auth.py
- Update test_jwt_access_token_skips_api_key_auth docstring to reference
  API_KEY_PASSTHROUGH_CLAIM instead of the legacy _api_key_passthrough name
- Add noqa: BLE001 to broad exception catch in mcp_config.py to document
  that the wide catch is intentional (JWT libs raise many types, secrets guard)
2026-05-13 06:34:46 +00:00
Amin Ghadersohi
76ad5e1bf7 fix(mcp): validate API keys via FastMCP AccessToken and lock down ApiKey perms
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.
2026-05-08 14:26:05 -04:00
Amin Ghadersohi
135579b8e1 fix(mcp): add type annotations to test fixtures and parameters
Address code review feedback: add explicit type annotations
to all new test function parameters and fixture return types.
2026-05-08 11:42:45 -04:00
Amin Ghadersohi
b9aee62f5f fix(mcp): wire composite verifier and add ApiKey permission sync
Wire CompositeTokenVerifier into create_default_mcp_auth_factory,
add _api_key_passthrough detection in _resolve_user_from_jwt_context,
create ApiKey permissions in create_custom_permissions, and update
test_auth_api_key with pass-through and non-matching prefix tests.
2026-05-08 11:42:45 -04:00
Amin Ghadersohi
7ad0b5e3f8 fix(mcp): create ApiKey permissions on init and support API keys with JWT auth
Two fixes for MCP API key authentication:

1. superset init now creates ApiKey FAB permissions (can_list, can_create,
   can_get, can_delete) when FAB_API_KEY_ENABLED=True. Previously, because
   Superset uses AppBuilder(update_perms=False), FAB skipped permission
   creation during blueprint registration and superset init never picked
   them up, causing 403 errors on /api/v1/security/api_keys/.

2. CompositeTokenVerifier allows API key tokens (e.g. sst_...) to coexist
   with JWT auth on the MCP transport layer. Previously, when
   MCP_AUTH_ENABLED=True, the JWTVerifier rejected all non-JWT Bearer
   tokens at the transport layer before they could reach the Flask-level
   _resolve_user_from_api_key() handler. The composite verifier detects
   API key prefixes and passes them through with a marker claim, letting
   the existing auth priority chain handle validation.
2026-05-08 11:42:45 -04:00
Richard Fogaca Nienkotter
549aff7cf9 fix(mcp): clarify chart preview URL metadata (#39731) 2026-04-29 12:37:40 -03:00
Daniel Vaz Gaspar
c7c9a17d6b fix(mysql): fallback to pymysql when MySQLdb is not installed in get_datatype() (#39729)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 14:40:39 +01:00
JUST.in DO IT
54f1e32763 fix(dashboard): escape emoji in position_json before saving to prevent truncation (#39737)
Co-authored-by: Michael S. Molina <michael.s.molina@gmail.com>
2026-04-29 10:08:50 -03:00
Amin Ghadersohi
4b42f82f13 fix(mcp): restore typed ChartConfig in tool schemas for LLM visibility (#39732) 2026-04-28 19:46:57 -04:00
Richard Fogaca Nienkotter
d0abb66fdf fix(mcp): default chart previews to ascii (#39719) 2026-04-28 13:30:39 -03:00
Amin Ghadersohi
6947881ba7 fix(mcp): classify user errors as WARNING, system errors as ERROR (#39634)
Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 08:55:17 -04:00
Michael S. Molina
c4a8b34b11 fix(query-history): enable sorting by Duration column (#39637)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 08:49:58 -03:00
Mehmet Salih Yavuz
3f28f5d012 fix(mcp): surface structured errors for generate_chart validation failures (#39484)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 11:13:53 +03:00
Amin Ghadersohi
7774ec7e3c fix(mcp): database filter columns, timeseries SQL, and unsaved chart datasource name (#39636) 2026-04-27 13:41:06 -04:00
Evan Rusackas
2026a1de6a fix(i18n): Fix menu bar translations not updating on language change (#34565)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Claude <claude@anthropic.com>
2026-04-24 22:49:03 -07:00
Amin Ghadersohi
ad20285dd6 fix(mcp): sanitize chart config errors and accept field name aliases (#39606) 2026-04-24 21:30:43 -04:00
Richard Fogaca Nienkotter
57e563b177 fix(mcp): redact dashboard data model metadata (#39632) 2026-04-24 17:37:15 -03:00
Beto Dealmeida
edf4d03218 chore: bump rison to 2.0.0 (#39529) 2026-04-24 15:52:42 -04:00
Enzo Martellucci
d7941ccfec fix(mcp): surface XSS sanitization in chart/dashboard names instead of silently stripping (#39491) 2026-04-24 14:59:20 +02:00
Richard Fogaca Nienkotter
d79eb5842a fix(mcp): protect data-model metadata from dashboard viewers (#39599)
Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 09:40:39 -03:00
Luiz Otavio
970b5bcf75 fix(cross-filter): correctly cast adhoc column types when cross filtering (#39577)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 08:26:46 -03:00
Amin Ghadersohi
7c4f87615b fix(mcp): correct method name in API key auth (extract_api_key_from_request) (#39437) 2026-04-23 23:33:23 -04:00
Elizabeth Thompson
f0d521dfc2 fix(reports): poll for spinner absence instead of snapshotting loading elements (#39579)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 22:03:43 -03:00
Amin Ghadersohi
012bf52c8c fix(mcp): resolve $ref by inlining definitions in compact schema (#39562) 2026-04-23 17:58:06 -04:00
Richard Fogaca Nienkotter
0d50fd676b fix(mcp): hide user directory metadata from responses (#39576)
Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 17:35:08 -03:00
Enzo Martellucci
dae79a6cba fix(mcp): surface validation errors in generate_chart instead of empty response (#39522)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 21:50:02 +02:00
Michael S. Molina
362e5bf45e fix(jinja): drill-to-detail respects remove_filter=True in Jinja templates (#39594)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 16:11:13 -03:00
Amin Ghadersohi
b1b6a057d8 fix(mcp): unwrap ToolResult payload before truncation in ResponseSizeGuardMiddleware (#39578)
Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
2026-04-23 12:35:13 -04:00
Joao Amaral
e10918307c fix(db): Add MariaDB DDL fix for NOCYCLE syntax (#37582) 2026-04-22 19:01:20 -04:00
Declan Zhao
4ee3a0fc07 feat(user_info): include Groups in user data payload when include_perms is True and show Groups on user_info page (#39450) 2026-04-22 11:14:59 -07:00
Vitor Avila
5af17c7976 fix(OpenSearch): OpenSearch dialect for sqlglot (#39538) 2026-04-22 12:17:15 -03:00
Amin Ghadersohi
e6853894ab chore(mcp): extract shared chart helpers and ASCII rendering into separate modules (#39438) 2026-04-21 20:10:49 -04:00
Gabriel Torres Ruiz
919daabe54 fix(mcp): clear stale query_context in update_chart so filters and row_limit are applied (#39413) 2026-04-21 14:34:21 -03:00
Amin Ghadersohi
29806780dc chore(mcp): remove dead parse_request decorator and utility code (#39498) 2026-04-21 11:16:06 -04:00
Vitor Avila
191337e08d fix(db oauth2): Improve OAuth2 flow (#39499) 2026-04-21 11:54:52 -03:00
Brian Schreder
a222dab781 feat(dashboard): pre-filter time grain (#38922) 2026-04-21 10:35:24 -04:00
Maxime Beauchemin
151d7d76da fix(charts): set g.form_data for metric() Jinja macro on GET chart data endpoint (#39347)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 19:36:03 -07:00
Beto Dealmeida
11607dde04 feat(sqllab): syntax validation for sqlite-based DB engine specs (#38698)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-04-20 18:29:51 -04:00
Beto Dealmeida
6535fdd556 chore: simplify Trino's OAuth detection (#39496) 2026-04-20 18:08:48 -04:00
Beto Dealmeida
5fb89b865d fix(oauth2): silence lock acquisition errors on token refresh (#39463)
Co-authored-by: Beto Dealmeida <beto@preset.io>
2026-04-20 18:08:33 -04:00
Amin Ghadersohi
6948e73ec7 feat(mcp): add get_chart_sql tool and expose chart filters in get_chart_info (#38700) 2026-04-20 17:50:10 -04:00
Maxime Beauchemin
c4cf03f899 fix(import): import tags during CLI native asset import (#39495)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:59:51 -07:00
Amin Ghadersohi
5cff657812 fix(mcp): default XY chart x-axis to dataset primary datetime column (#39421)
Co-authored-by: codeant-ai-for-open-source[bot] <244253245+codeant-ai-for-open-source[bot]@users.noreply.github.com>
2026-04-20 11:14:54 -04:00
Alexandru Soare
0857611a4e fix(mcp): Add defensive validator for ColumnInfo.is_nullable (#39365) 2026-04-20 13:50:31 +03:00
Geidō
51ea2c297d fix(dataset): calculated columns in virtual datasets fail when used as dynamic aggregation filter dimensions (#39004)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 13:44:53 +03:00
Gabriel Torres Ruiz
2e0d482ccf fix(mcp): support explicit query_mode in TableChartConfig (#39412) 2026-04-16 18:53:25 -03:00
Gabriel Torres Ruiz
e5b3a9c25d fix(mcp): replace inputSchema with parameters_hint in search_tools results by default (#39411) 2026-04-16 18:53:10 -03:00