feat(authorization): light up IResourceSecurityContext<TResource> in Mediator dispatch#98
Merged
MarcelRoozekrans merged 6 commits intoMay 23, 2026
Conversation
…option Lights up IResourceSecurityContext<TRequest> (dormant contract shipped in ZeroAlloc.Authorization v2.1) by wrapping the resolved ISecurityContext in a per-dispatch ResourceSecurityContextAdapter<TRequest> before calling AuthorizerFor<TRequest>.EvaluateAsync. The dispatched request becomes the typed resource. Always-wrap (no opt-in surface), ~16 B per dispatch. Pure runtime additive behaviour — no PublicAPI change. Lands as a feat: minor bump for Mediator.Authorization. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rce context Task-by-task plan covering adapter creation, AuthorizationBehavior wrap, 2 runtime tests, conditional allocation-budget bump, docs section, and push + admin-merge. Follows the precedent of the 2026-05-22 integration tests plan.
…ource> Per-dispatch adapter that implements IResourceSecurityContext<TResource> (shipped dormant in ZeroAlloc.Authorization v2.1) by wrapping an inner ISecurityContext + a resource value. ISecurityContext members forward to the inner; Resource exposes the wrapped value. Not wired into AuthorizationBehavior yet — that's the next commit. Internal-only; no PublicAPI change.
AuthorizationBehavior.Handle now wraps the resolved ISecurityContext in a ResourceSecurityContextAdapter<TRequest> before passing to the authorizer. Policies that type-check ctx is IResourceSecurityContext<TRequest> rc now resolve correctly; policies that ignore the resource see the same ISecurityContext members as before. Cost: ~16 B class allocation per dispatch (one object header + two reference fields). Absorbed by the existing AuthorizationBehavior.Handle budget; see AllocationBudgetTests. Lights up ZeroAlloc.Authorization v2.1's IResourceSecurityContext<TResource> contract for Mediator dispatch.
Two runtime tests on AuthorizationBehavior.Handle:
- Policy_Sees_DispatchedRequest_AsResource: a [Policy] that type-checks
IResourceSecurityContext<ResourceOwnerCommand> sees the dispatched
request and allows when ctx.Id == request.UserId.
- Policy_TypeChecking_WrongRequestType_FallsThrough: a [Policy] that
type-checks the WRONG TResource (intentionally mismatched) hits the
cast's false branch and denies.
Adds ResourceOwnerPolicy / ResourceWrongTypePolicy and their request
records to TestFixtures.cs. Tests run under the existing
[Collection("non-parallel-authorization")] guard because they set the
static AuthorizationBehaviorState.ServiceProvider.
Documents how to write a policy that inspects the dispatched request as a typed resource via IResourceSecurityContext<TRequest>. Mediator wraps the resolved ISecurityContext per-dispatch so the cast resolves automatically — no host configuration. Links out to ZeroAlloc.Authorization's resource-based-authorization.md for the underlying contract.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lights up the dormant
IResourceSecurityContext<TResource>contract shipped inZeroAlloc.Authorizationv2.1.0 (PR #28, released today).AuthorizationBehavior.Handlenow wraps the resolvedISecurityContextin an internal adapter that exposes the dispatchedTRequestasResource. Consumer policies that type-checkctx is IResourceSecurityContext<TConcreteRequest> rcnow resolve correctly — no consumer changes required beyond writing the resource-based policy.Why
ZeroAlloc.Authorizationv2.1 shipped the contract dormant — the interface exists, but no host populates it.Mediator.Authorizationis the natural first host: it already resolves anISecurityContextfrom DI per dispatch and callsAuthorizerFor<TRequest>.EvaluateAsync(ctx, ct). The change is a fully-additive wrap before that call.Design + plan
docs/plans/2026-05-23-mediator-authorization-resource-context-design.mddocs/plans/2026-05-23-mediator-authorization-resource-context.mdWhat changed
src/ZeroAlloc.Mediator.Authorization/ResourceSecurityContextAdapter.cs—internal sealed class ResourceSecurityContextAdapter<TResource> : IResourceSecurityContext<TResource>forwardingISecurityContextmembers to an inner context. No PublicAPI change.src/ZeroAlloc.Mediator.Authorization/AuthorizationBehavior.cs— 2-line wrap ofctxbefore theauthorizer.EvaluateAsync(...)call.tests/ZeroAlloc.Mediator.Authorization.Tests/ResourceSecurityContextTests.cs— 2 runtime tests covering the resource-resolves and wrong-type-falls-through cases.tests/ZeroAlloc.Mediator.Authorization.Tests/TestFixtures.cs— addsResourceOwnerPolicy/ResourceWrongTypePolicy+ their request records and stub handlers.docs/authorization.md— new "Resource-based policies" section linking out toZeroAlloc.Authorization'score-concepts/resource-based-authorization.md.Task 4 (allocation-budget bump) from the plan was skipped because the existing 512 B
AuthorizationBehavior.Handlebudget already absorbs the ~16 B/dispatch adapter allocation — verified byAllocationBudgetTestspassing without modification.Allocation cost
One ~16 B class allocation per dispatch (object header + 2 reference fields + method-table pointer). Absorbed by the existing
AuthorizationBehavior.Handleallocation budget; seeAllocationBudgetTests.Test plan
Id/Roles/Claimstransparently); local 33/33 pass.TResourcecases.AuthorizationBehavior.Handleallocation budget still respected without modification.Out of scope
AI.Sentineladoption of the same pattern. Tracked separately.IHasResource<TResource>sub-property extractor. Sub-properties go throughrc.Resource.X.Yinside the policy body.🤖 Generated with Claude Code