cmcfarlen opened a new issue, #13607:
URL: https://github.com/apache/trafficserver/issues/13607

   # access_control: implement the `scope` claim so a token authorizes only its 
own resources
   
   ## Summary
   
   The `access_control` plugin parses a `scope` claim out of the access token 
and exposes it, but
   never compares it to anything. `AccessToken::validate()` checks syntax, 
required claims, the
   HMAC signature, and the timing claims, then returns — it takes no 
request/resource argument and
   ends with a placeholder:
   
   `plugins/experimental/access_control/access_control.cc:64`
   
   ```cpp
     /** @todo: validate scope eventually */
   
     return _state;
   ```
   
   The consequence is that any token valid for a remap rule is valid for every 
resource that rule
   covers. There is no way to mint a token that is accepted for one path and 
refused for another.
   
   This is currently documented behavior rather than a defect — the admin guide 
says of the
   `scope` claim (`doc/admin-guide/plugins/access_control.en.rst:240`):
   
   > `scope` for scope_, `optional`, ignored by the current version of the 
plugin, still not
   > finalized (more applications and their use cases need to be studied to 
finalize the format)
   
   This issue is a request to finish the feature, and a proposal for what 
"finalized" could mean.
   
   ## Current state
   
   Everything except the comparison is already in place:
   
   | Piece | Location |
   |---|---|
   | `scope` parsed from the token | `access_control.cc:223` (`_scope = 
value;`) |
   | `getScope()` accessor | `access_control.h:157` |
   | `INVALID_SCOPE`, `OUT_OF_SCOPE` states | `access_control.h:101-102` |
   | `--invalid-scope-status-code` option (default 403) | `config.cc:176`, 
`config.h:48` |
   | That status wired into a response | `plugin.cc:187` |
   
   `getScope()` has no caller outside `unit_tests/test_access_control.cc:67`, 
and the member is
   itself annotated `still @todo` (`access_control.h:205`).
   
   The request path *is* available at the point where the token is checked.
   `TSRemapDoRemap()` reads it (`plugin.cc:588`) and passes it to
   `config->_uriPathScope.matchAll()` (`plugin.cc:600`), but that classifier 
only decides
   *whether* to enforce access control for a path — an admin-side allow/deny 
list — not *which*
   resources a given token may reach. On a match it calls 
`enforceAccessControl()`
   (`plugin.cc:604`), which validates the token (`plugin.cc:527`) without the 
path being involved.
   
   ## Why it is worth finishing
   
   The plugin already treats the token's `sub` claim as a *target audience* 
rather than a
   resource: the docs describe it as "an application specific audience (role, 
group of users,
   etc)", the worked example uses values like `frogs-in-a-well` and 
`fish-in-a-sea`, and audience
   separation is achieved through the cache key (via the `cachekey` plugin) 
rather than through
   authorization. That model is deliberate and works.
   
   What is missing is any per-resource granularity for deployments that want 
it. An operator who
   wants "this token is good for `/reports/2026/` and nothing else" has no 
mechanism, and the
   presence of a `scope` claim plus an `--invalid-scope-status-code` option 
reasonably suggests
   one exists. Implementing `scope` closes that gap and makes the option 
meaningful.
   
   It also removes a small footgun: an operator can set 
`--invalid-scope-status-code` today and
   get no behavior from it.
   
   ## What implementing it requires
   
   More than a bounds check, which is presumably why it was deferred:
   
   1. **A matching semantic.** Exact match, path-prefix, or pattern? Prefix is 
the obvious
      default for a CDN path namespace, but it needs to be stated, and prefix 
matching has to be
      defined on normalized path segments so that `/reports2/` is not accepted 
by a `/reports`
      scope.
   2. **Behavior when `scope` is absent.** Tokens in the field today have no 
`scope`. Absent must
      keep meaning "no restriction", or every existing token breaks. That 
argues for the check
      being opt-in per remap rule, or keyed off the claim's presence.
   3. **What the scope is matched against.** The remapped path, the pre-remap 
path, or the path
      plus host? These differ once remap rules rewrite the URL, and the answer 
determines whether
      a scope is portable across rules.
   4. **Plumbing.** `validate()` needs the resource passed in, or the scope 
check needs to move to
      a separate call that `enforceAccessControl()` makes after `validate()` 
succeeds. The former
      changes a public-ish signature within the plugin; the latter keeps 
`validate()` purely about
      token integrity, which may be the cleaner split.
   5. **The format itself**, which is what the docs call out as unfinished — a 
single path, a list,
      or something structured.
   
   `INVALID_SCOPE`/`OUT_OF_SCOPE` and the configured status code give the 
failure path somewhere to
   land, so the reporting side needs no new design.
   
   ## Suggested scope for a first change
   
   A minimal, backward-compatible version:
   
   - Add a scope check that runs after `validate()` succeeds, taking the 
request path.
   - Treat an absent or empty `scope` claim as unrestricted, so existing tokens 
are unaffected.
   - Match as a path-prefix on normalized segments.
   - Return `OUT_OF_SCOPE` on failure so `--invalid-scope-status-code` applies.
   - Document the matching rule and the absent-claim behavior, replacing the 
"ignored by the
     current version" note.
   - Extend `unit_tests/test_access_control.cc`, which already covers 
`getScope()` parsing, to
     cover the comparison.
   
   Anything richer than a prefix — lists, patterns, host-qualified scopes — 
could follow once the
   format question is settled.
   
   ## Notes
   
   - The plugin is experimental and off by default 
(`BUILD_EXPERIMENTAL_PLUGINS`), so this changes
     nothing for a stock build.
   - Line references are against `master` at `d01f3caf6a`.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to