Skip to content

fix(pelican): require authentication on the federation routes - #264

Merged
rbardaji merged 1 commit into
mainfrom
fix/261-protect-pelican-routes
Aug 30, 2026
Merged

fix(pelican): require authentication on the federation routes#264
rbardaji merged 1 commit into
mainfrom
fix/261-protect-pelican-routes

Conversation

@rbardaji

Copy link
Copy Markdown
Collaborator

Closes #261.

What was wrong

The five routes under /pelican were mounted with no authentication and no authorization. The module never imported Depends, the router carried no dependencies, and the only middlewares on the application are correlation IDs and CORS, so nothing gated them anywhere along the path.

Verified against the real application rather than by reading the code — with PELICAN_ENABLED=true and no Authorization header, GET /pelican/federations returned 200 and the federation list. The same request with the router unmounted returns 404, which is what rules out the response coming from an unmatched path.

Anyone able to reach the port could enumerate a namespace, stream files out of the configured federation via /download, and attach resources to an existing package via /import-metadata, which writes.

PELICAN_ENABLED hid the problem rather than solving it: it decides whether the router is mounted, so the routes were closed only on deployments that had Pelican switched off entirely.

The change

  • The router carries dependencies=[Depends(get_user_for_read_operation)], covering all five routes.
  • /import-metadata additionally takes get_user_for_write_operation, the dependency used by every other route that writes to the catalog.

The read gate is declared on the router rather than repeated on each route deliberately. This bug happened because five routes were added and the authorization was missed on all five; a router-level dependency means a sixth route inherits it instead of shipping open.

No new mechanism was introduced — both dependencies already existed in api/services/auth_services/authorization_service.py. The docstring of get_user_for_read_operation already described itself as available for exactly this case.

Verification

Against the real app (api.main):

Scenario Result
PELICAN_ENABLED=false, no token 404 (router not mounted)
PELICAN_ENABLED=true, no token, before this change 200 + federation list
PELICAN_ENABLED=true, no token, after this change 401
PELICAN_ENABLED=true, valid token 200

Seven new cases in tests/test_pelican_routes.py: anonymous caller rejected, authenticated user with no role tier rejected, viewer allowed to read, viewer rejected on /import-metadata, writer allowed. On /browse and /download the tests also assert the Pelican service is never called, confirming the request is cut before it reaches the federation.

Local gate: black and flake8 clean, 1273 tests pass. Three failures in tests/repositories/test_catalog_settings.py and tests/test_publi_env.py predate this branch — they reproduce on a clean main and are caused by a local .env being picked up by the settings tests, which does not exist in CI.

Backwards compatibility

Callers of /pelican/* must now send a bearer token and hold a viewer, writer or admin role on the endpoint — writer or admin for /import-metadata. An anonymous request that used to succeed returns 401, and an authenticated user without a role tier gets 403.

No web UI code calls these routes, so the admin console is unaffected. Scripts and notebooks that reached them without a token need updating. Deployments running with PELICAN_ENABLED unset are unaffected.

Every route under /pelican was mounted with no authentication and no
authorization, so any caller reaching the port could browse a namespace,
stream files out of the federation and attach resources to a package.
PELICAN_ENABLED only decided whether the router was mounted, so the
routes were open on every deployment that had Pelican switched on.

Gate the router with the read-tier dependency and give /import-metadata
the write-tier one used by the rest of the registration routes. The read
gate lives on the router rather than on each route so a Pelican route
added later cannot ship open the same way.

Closes #261
@rbardaji
rbardaji merged commit a7a2095 into main Aug 30, 2026
2 checks passed
@rbardaji
rbardaji deleted the fix/261-protect-pelican-routes branch August 30, 2026 18:21
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.

Pelican federation routes are exposed without authentication

1 participant