diff --git a/backend/windmill-api-auth/src/auth.rs b/backend/windmill-api-auth/src/auth.rs index af6e8287fb..0eee06f1e0 100644 --- a/backend/windmill-api-auth/src/auth.rs +++ b/backend/windmill-api-auth/src/auth.rs @@ -526,28 +526,17 @@ impl AuthCache { } } } - // A guest session: authenticated by the IdP, - // member of nothing. Deliberately no `usr` - // lookup and no groups or folders, so every - // ACL denies it on its own and the token's - // scopes are its entire grant - // (`guest_route_denied`). Placed after the - // superadmin arm so a superadmin token can - // never be demoted into this one. - // - // Keyed on the server-minted label, never on - // the `guest` scope: this arm is the only - // thing in the codebase that turns "no `usr` - // row" from a rejection into an identity, and - // scopes on a user-minted token are whatever - // the caller typed. + // A guest session: IdP-authenticated, member of + // nothing. No `usr` lookup, groups or folders, so + // every ACL denies it and the token's scopes are + // its whole grant. After the superadmin arm, so + // that token is never demoted into this one. None if is_guest_session => { - // The label is the grant; every guest - // control downstream keys on the `guest` - // sentinel. Pin the two together here so - // a credential that carries the label is - // governed as a guest whatever its scopes - // say — nothing else may decide that. + // The server-minted label is the grant, never + // the `guest` scope (a user-minted token's + // scopes are whatever the caller typed); the + // sentinel is pinned on here so every guest + // control downstream sees a guest regardless. let scopes = Some(crate::scopes::with_guest_sentinel( scopes.unwrap_or_default(), )); diff --git a/backend/windmill-api-users/src/users.rs b/backend/windmill-api-users/src/users.rs index 147cc94677..679b7dcfd5 100644 --- a/backend/windmill-api-users/src/users.rs +++ b/backend/windmill-api-users/src/users.rs @@ -2957,24 +2957,18 @@ fn guest_session_scopes(app_path: &str) -> Vec { } /// Mint a browser session for someone the identity provider authenticated who is a -/// member of no workspace, so they can open one guest-mode app. +/// member of no workspace, so they can open one guest-mode app. Writes no `password` +/// and no `usr` row: that absence is what keeps a guest off every seat counter, so +/// nothing here may be "helpfully" upgraded into provisioning. /// -/// Writes no `password` and no `usr` row: that absence is what keeps a guest off every -/// seat counter, so nothing here may be "helpfully" upgraded into provisioning. +/// Pinned to `w_id` (`AuthCache` matches on `token.workspace_id`): without the pin an +/// `apps:run:` scope would unlock a same-path app elsewhere. So a guest cannot +/// authenticate on any workspace-less route (`/api/users/*`, `/api/settings/*`); a +/// page that needs one for a guest must become workspace-scoped, not loosen the pin. /// -/// The token is pinned to `w_id`: `AuthCache` matches on `token.workspace_id`, and -/// without the pin an `apps:run:` scope would also unlock a same-path app in -/// another workspace. The pin also means a guest cannot authenticate on any -/// workspace-less route at all — `/api/users/*`, `/api/settings/*` — since those -/// resolve with a NULL workspace and the match fails. That is the intent, and the -/// chrome-less public app page calls none of them; a page that needs one for a guest -/// has to become workspace-scoped rather than the pin being loosened. -/// -/// Refuses unless both gates say yes — the workspace admits guests and `app_path` is -/// currently in `guest` execution mode — so no caller can mint a guest session where -/// one is not wanted, whatever it believed when it decided to call. The one thing left -/// to the caller is the authentication of `email`: this function trusts only that the -/// identity provider vouched for who is asking. +/// Refuses unless every gate says yes (`guest_app_admits`), so no caller can mint where +/// a guest is not wanted, whatever it believed when it decided to call. All that is +/// left to the caller is the authentication of `email`. pub async fn create_guest_session_token<'c>( email: &str, w_id: &str,