Skip to content

Hotfix: every request authenticates as its own user - #265

Merged
fcollman merged 1 commit into
masterfrom
reset-auth-every-request
Oct 27, 2026
Merged

fcollman merged 1 commit into
masterfrom
reset-auth-every-request

Conversation

@fcollman

Copy link
Copy Markdown
Collaborator

Problem

configure_app pushed an app context that was never popped. Flask 2.3 reuses an already active app context for a request instead of pushing its own, so flask.g outlived each request within a uWSGI worker process. middle_auth_client's auth_required skips authentication when flask.g.auth_token is already set.

On any endpoint without @reset_auth, a request ran as whoever that worker last authenticated, including a request with no token at all. That covered most of upload/api.py (inspect, start, cancel, status, user-jobs, admin cleanup) and the datastack/table views in views.py. Requests were:

  • wrongly refused, such as the intermittent Missing permission: edit for dataset minnie65 from the upload wizard's inspect step;
  • or wrongly allowed, with another user's permissions.

Reproduced on minnie (v5.33.0) with the app's test client: a request with a token, then one without, and the second returned 200 as the first user.

Fix

  • configure_app no longer pushes an app context. It was added in 2019 (f01dd3d) so early celery tasks could read current_app. Tasks now run in their own context (ContextTask), as do the Ray entrypoints and Ray workers, and the celery signal handlers either don't use the app or push their own context. Code with no context falls back to the environment, as before, through get_config_param.
  • create_app registers a before_request hook that clears flask.g.auth_token and flask.g.auth_user, so no endpoint depends on carrying a decorator.
  • The per-endpoint @reset_auth decorators are removed.

Tests

tests/test_reset_auth.py:

  • shows the leak on an app without the hook;
  • checks that, with the hook, a request with no token after an authenticated one gets a 401, and each request runs as its own token's user;
  • checks that edit permission follows the request's token;
  • checks that configure_app leaves no context pushed.

Full suite on a fresh PostGIS: 701 passed, 2 skipped.

🤖 Generated with Claude Code

configure_app pushed an app context that was never popped. Flask reuses an active
app context for a request instead of pushing its own, so flask.g outlived each
request within a uWSGI worker, and middle_auth_client's auth_required skips
authentication when flask.g.auth_token is already set. A request to any endpoint
without @reset_auth ran as whoever that worker last authenticated, with no token
at all included: wrongly refused (a 403 for a user who has the permission) or
wrongly allowed (another user's, or an admin's, permissions).

- configure_app no longer pushes an app context. It was added in 2019 so celery
  tasks could read current_app; tasks now run in their own context (ContextTask),
  as do the Ray entrypoints and workers.
- create_app registers a before_request hook that clears flask.g.auth_token and
  flask.g.auth_user, so no endpoint depends on carrying a decorator.
- The per-endpoint @reset_auth decorators are removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@fcollman
fcollman merged commit 24ac8d4 into master Oct 27, 2026
1 check passed
fcollman added a commit that referenced this pull request Oct 29, 2026
#265 stopped configure_app pushing an app context for the process, relying on
ContextTask for every task. Four tasks never had it, and since then fail on
their first current_app access: run_periodic_materialization (no minnie
frozen version on Oct 28 or 29), run_periodic_database_update,
remove_expired_databases and update_database_workflow.

- create_celery sets ContextTask before anything reads celery.conf. The first
  read fires on_after_configure, and setup_periodic_tasks builds the scheduled
  tasks then, from whatever celery.Task was at that moment.
- LockedTask, a base of its own, enters the same app context in __call__
  (call_in_app_context, shared with ContextTask).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant