Repository navigation
Conversation
A dashboard load asks can_access the same few questions once per member dataset (all_datasource_access, all_database_access, the database, catalog and schema permissions), and each answer is a query against the role tables. On a dashboard of 72 virtual datasets, a viewer granted one of them asked 77 distinct questions 1,155 times on each of /dashboard/<id>, /charts and /datasets; an admin passes the first question. remember_view_access puts a memo on the request, and can_access reuses its answers, per user, for the rest of that request. Only the three dashboard-load routes carry it; every other request, CLI command and task asks each time. On get it sits above @with_dashboard, so the dashboard's own access check is covered too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| @protect() | ||
| @handle_api_exception | ||
| @statsd_metrics | ||
| @remember_view_access |
There was a problem hiding this comment.
Suggestion: After the first datasource check succeeds, this request-wide memo keeps later checks authorized even after a concurrent grant revocation, exposing subsequent dataset metadata.
Assessment: 🟠 Major · 🔁 Occurrence: Rarely · 🏷️ Security
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** superset/dashboards/api.py
**Line:** 837:837
**Comment:**
*Security: After the first datasource check succeeds, this request-wide memo keeps later checks authorized even after a concurrent grant revocation, exposing subsequent dataset metadata.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #46026 +/- ##
=======================================
Coverage 65.42% 65.42%
=======================================
Files 3082 3082
Lines 210951 210976 +25
Branches 49720 49724 +4
=======================================
+ Hits 138006 138031 +25
Misses 69768 69768
Partials 3177 3177
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
gabotorresruiz
left a comment
There was a problem hiding this comment.
Thanks @uhyunpark, nice improvement. I compared the three routes on master and on this branch across admin, Gamma with and without dataset grants (direct and via a group role), dashboard viewers, JWT, embedded guest tokens and anonymous with a Public role, and every status and body matched; the call counts in the description reproduce. CI is green. Two non-blocking notes inline.
Under session auth FAB sets g.user to flask-login's current_user, a single module-level proxy, so id(user) was the same for every user and the owner check could not tell two users apart. can_access now unwraps the proxy before keying the memo, and the cross-user test switches users through login_user with g.user = current_user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/tabs looks the dashboard up twice (get_tabs_for_dashboard and get_native_filter_configuration), and each lookup walks every member dataset. With the memo the second walk is answered from the first. The route test keeps a negative control through /embedded, which runs the same lookup without the memo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Sorry for late, I was a bit busy in the weekend. I commented / updated my PR. Thanks for the review! |
SUMMARY
Loading a dashboard checks access to every member chart's datasource. Each check asks
can_accessthe same few questions (all_datasource_access,all_database_access, then the database, catalog and schema permissions), and each answer is a query against the role tables. An admin passes on the first question; a viewer with access to few of the datasets goes through all of them, for every dataset.On a dashboard of 72 charts over 72 datasets, a viewer granted one of them asks 77 distinct questions 1,155 times per request, on each of
/dashboard/<id>,/chartsand/datasets.This PR lets
can_accessreuse its answers within those three requests:remember_view_access, a new decorator, puts an empty memo on the request.can_accessuses it only when present, so all other routes, CLI commands and Celery tasks ask every time.flask.g, and is keyed by the user object, so answers never cross requests or users.getit sits above@with_dashboard, so the lookup's own access check is covered.Unchanged: every access decision.
_has_view_accessdepends only on the user's roles (direct and through groups), the permission and the view menu, none of which change during these read-only requests. Only these permission answers are reused; each dataset is still checked on its own. Anonymous users still go throughis_item_public.BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A (no UI change). Measured on master with a SQLite metadata database: 72 charts on 72 virtual datasets, a Gamma viewer granted
datasource_accesson one of them, median of 5 calls per route._has_view_accesscallsGET /api/v1/dashboard/<id>GET /api/v1/dashboard/<id>/chartsGET /api/v1/dashboard/<id>/datasetsdatasource_access, plus 5 shared./datasets(73 → 2 calls).TESTING INSTRUCTIONS
pytest tests/unit_tests/security/can_access_memo_test.py:/tabs; moving the decorator below@with_dashboardfails this test.ADDITIONAL INFORMATION
🤖 Generated with Claude Code