Skip to content

session/security: IAuthorizer::authorize also gates 'instances' and 'schemas' with an empty actionType, but is documented as execute-only #500

Description

@Yaraslaut

Summary

IAuthorizer::authorize's doc says it is "Called once per execute envelope". RemoteServer also calls it on instances and schemas, passing an empty actionType. An authorizer written as an allowlist over actionType — the shape the parameter doc invites — therefore evaluates against "" on the two disclosure channels.

Verification status

Verified by reading the call sites. Not exercised against a real IAuthorizer implementation; I have not shown a concrete policy failing open.

grep -n "_authorizer->authorize" include/morph/core/remote.hpp:

1192:  if (!_authorizer->authorize(env.session, env.typeId, {})) {     <- instances
1209:  if (!_authorizer->authorize(env.session, env.typeId, {})) {     <- schemas
1317:  if (!_authorizer->authorize(env.session, env.modelType, env.actionType)) {   <- execute

The server side is deliberate and says so (remote.hpp:1188-1191, :1201-1207: "gate it with authorize for the model type (empty action id)"). The interface doc is the stale side.

Why it matters more than a wording nit

session.hpp:111 documents @param actionType as "String id of the action being invoked", with no note that it can be empty. An implementation that switches or matches on actionType will hit its default arm for instances and schemas — and schemas returns, per remote.hpp:1204-1206, "field names, bounds, rules and the payload fingerprint of every action". Whether that fails open or closed depends entirely on how the embedder wrote the default, and nothing in the contract tells them the case exists.

SigningAuthorizer::Policy (session_auth.hpp:521-526) has the same gap: its doc says only "the target ids".

docs/spec/session/session.md:416 repeats the stale claim ("Called per execute envelope"), so header and spec agree with each other and disagree with the code.

What would change the verdict

  • Close it by correcting the three doc sites — that is very likely the whole fix; the server behaviour looks correct and intentional.
  • Raise it if any shipped or example authorizer is shown to fail open on the empty actionType.

Adjacent, same file

SigningAuthorizer runs a full token verification twice per requestauthorize() (session_auth.hpp:572) and authenticate() (:583) each call _verifier.verify(ctx.token, _clock()). That is two base64url decodes, two HMAC-SHA256 passes and two Glaze parses per authenticated request, from two separate clock samples. remote.hpp:1323-1330 documents the resulting expiry window; none of the three doc blocks in session_auth.hpp mention that verification is repeated or that the two calls can disagree. Also session_auth.hpp:470 builds std::string{payload} for a string_view parameter, allocating on every verification — so twice per request.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: sessionSubsystem: sessiontriage: rescopeReal problem, wrong framing; rewrite before building

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions