A Spring method authorization rule can reject a tenant-scoped write before its service method changes state.
Spring method security: reject a cross-tenant receipt mutation
Call through the managed service
The source-kit context enables method security and retrieves ReceiptWriter from the container. An authenticated tenant-east call changes its own receipt to reviewed. A tenant-west call through the same managed object throws AccessDeniedException; the west entry remains absent. This checks that the proxy applies the rule before entering the method.
The test uses a local authentication token and a HashMap, not an HTTP request, real identity provider or repository query. The tenant argument comes from the caller in the fixture, so a production service must derive and validate tenant scope against trusted authentication and constrain its database UPDATE by tenant and receipt ID. The read lesson covers the corresponding read boundary.
Proxy rules have a call-path limit
A direct call within the same class can bypass proxy advice. Tests must obtain the managed bean and call the secured method through it. The rule also needs coverage for asynchronous work, event listeners and internal commands that may run without the same request security context. Proxy self-invocation explains the dispatch boundary.
Checked source
@PreAuthorize("#p0 == authentication.name")
public void change(String tenant, int receiptId, String next) {
states.put(tenant + ":" + receiptId, next);
}Verification boundary
TenantReceiptWriteTest.managedServiceRejectsACrossTenantMutationBeforeTheMethodRuns runs in the downloadable Spring source kit. The excerpt leaves out surrounding setup and imports; the kit contains the complete test.
Costs and limits
The in-memory write is expected O(1) average time and has no database isolation or persistence. The test proves this managed bean denies one cross-tenant mutation. It does not prove the HTTP filter, tenant mapping, database row scope or cross-process state.
Common Mistakes
- Do not trust a tenant ID supplied only by the request body.
- Do not call the secured method through this when expecting proxy advice.
- Do not authorize a service and then issue an unscoped database UPDATE.
Read next
Spring method authorization: reject a cross-tenant read, Spring method authorization: test the proxied service boundary, Spring POST idempotency keys: replay the same receipt result.
Continue with checked tenant security
Continue with Spring JdbcTemplate tenant predicates: put ownership in the SQL query.
