Repository navigation
feat(middleware): admit one calling service by its sourceService claim - #229
Conversation
RequireSourceService(service) admits an application principal whose sourceService claim equals service and refuses every other caller with 403 (401 when no principal was published). It reads the stored Principal directly, so it decides under the legacy authorization model too, where PrincipalFromContext reports no application principal because the Subject is a fabricated role. The authorization round-trip vouched for the whole token in both models. The Lerian engines need it to admit only the JD Courier on their cross-core payee routes, which book against an unlimited-overdraft clearing account.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (3)
Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour. 📝 WalkthroughWalkthroughThe pull request adds ChangesSource service guard
Sequence Diagram(s)sequenceDiagram
participant Request
participant Authorize
participant RequireSourceService
participant NextHandler
Request->>Authorize: authorize request
Authorize->>RequireSourceService: pass request with Principal
RequireSourceService->>NextHandler: continue on exact application claim match
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to No actionable merge-blocking issue is identified; the change is ready for normal merge checks. ✨ Finishing Touches✨ Simplify code
Comment |
|
🎉 This PR is included in version 5.8.0-beta.1 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 5.8.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
What changes
middleware.RequireSourceService(service string) fiber.Handler, a sibling ofRequireApplication. Mount it afterAuthorize. It admits only an application principal whosesourceServiceclaim equalsserviceexactly:401(fiber.ErrUnauthorized)sourceService == serviceundeclared, empty, or a different case/spacing403(fiber.ErrForbidden)403serviceempty or theundeclaredmarkerThe guard returns Fiber errors, as the type guards do, so a service's own
ErrorHandlerkeeps its envelope.Why it reads the stored Principal instead of
PrincipalFromContextWhen
AUTH_M2M_INVERSION_ENABLEDis off (the default, and how every Lerian engine runs today),Authorizeauthorizes an application under the fabricatedadmin/<product>-editor-role.PrincipalFromContexttherefore reports no application principal at all. The token's claims are attested in both models anyway: the authorization service introspects the token on every cache miss, and both decision caches key on the token digest. The guard decides on the claims, never onSubject, so the rule that a legacy Subject is not an identity still holds. TheSourceServicedocstring and the README now say this.Who needs it
The Pix (plugin-br-pix-jd #409) and TED (plugin-br-bank-transfer #481) engines' cross-core payee routes book a credit by debiting
@intercore, a clearing account with unlimited overdraft. Today any application aimed at the engine, and any human editor, passescross_coreand can post a credit. With this guard only the JD Courier passes: an application issued with sourcejd-courier, whosesourceServicethe Access Manager stamps server-side. The guard is only as strong as the issuer: whoever may create applications for the tenant can issue one with that source. The README states this.Crippling proof (each sabotage applied alone, then reverted)
p.Type != applicationTestRequireSourceService/normal_user_is_403IsDeclaredSourceService.../empty_service_admits_nobody,.../marker_service_admits_nobodyp.SourceService != service.../another_source_is_403,.../match_is_exactPrincipalFromContext.../legacy_fabricated_subject_reaches_the_handler, plusTestRequireSourceService_BehindAuthorizeatinversion=false(the Courier gets 401 instead of passing)Verification
go test ./... -race -count=1passesgolangci-lint run ./...: 0 issues;goimports -l: cleanTestRequireSourceService_BehindAuthorizeruns the realAuthorizechain against a fake authorization service with inversion off and with inversion on.Line delta
prod +29/-8 (
principal.go: the guard plus the docstring rewrite), test +91/-0, docs +27/-7 (README).Pull Request Type
Checklist
🤖 Generated with Claude Code