Moves the existing virtual-thread/context-propagation project into context-propagation/ and adds method-security/ for the Spring Security 7 method-security article: nine runnable demos, fourteen assertions, and every transcript the article quotes, regenerated by scripts/run-all.sh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RSrsDSRKVsY588yFiMJMo9
method-security
Companion module for Method Security in Spring Security 7: @PreAuthorize, @PostAuthorize
and the Proxy Traps
on ankurm.com.
Nine small programs and a JUnit suite, each answering one question about what
@PreAuthorize and its siblings actually do at runtime — including the three cases where they
do nothing at all and say nothing about it. No web layer, no Boot application, no server: a
plain AnnotationConfigApplicationContext, a SecurityContextHolder, and real proxied beans,
so every result is about method security and not about a filter chain.
Part of spring-security-demo; the sibling module is context-propagation.
Verified versions
| Component | Version |
|---|---|
| JDK | 25 (Temurin 25.0.4.1+1), LTS |
| Spring Boot (reference target) | 4.1.1 |
| Spring Framework | 7.0.9 |
| Spring Security | 7.1.1 (-core, -config, -test) |
| AspectJ Weaver | 1.9.25 (only for exposeProxy in Demo 2) |
| Spring Data Commons | 4.1.1 (only so Demo 5 can filter a real Page) |
| H2 | 2.4.240 (Demo 6's transaction rollback proof) |
| JUnit Jupiter | 6.0.3 |
| AssertJ | 3.27.7 |
Latest GA on Maven Central at the time of writing, taken from maven-metadata.xml.
4.2.0-M1 / 7.2.0-M1 exist as milestones only.
Quickstart
mvn dependency:build-classpath -Dmdep.outputFile=cp.txt
javac --release 25 -parameters -cp "$(cat cp.txt)" -d target/classes $(find src/main -name '*.java')
java -cp "target/classes:$(cat cp.txt)" com.ankurm.methodsec.Demo2SelfInvocation
-parameters matters: without it every #parameterName expression in this module silently
stops working, which is what Demo 9 is about.
Everything at once, regenerating docs/output/: scripts/run-all.sh.
Just the assertions: mvn test.
What each demo shows
| Demo | Question | Chapter |
|---|---|---|
Demo1AnnotationsInAction |
What do all six annotation families do on the happy path, and what is thrown when they deny? | docs/01 |
Demo2SelfInvocation |
Why does an annotated method called from inside its own class run unchecked, and what are the three fixes? | docs/03 |
Demo3NonProxyable |
Which of final / static / private / package-private / final-class / interface-only actually get advised? |
docs/04 |
Demo4SpelReference |
Every expression you can write inside the annotation, evaluated as two different users | docs/02 |
Demo5FilteringTraps |
Which container types can @PreFilter / @PostFilter handle, and what happens on an immutable one? |
docs/05 |
Demo6InterceptorOrder |
Where does the security advice sit relative to @Transactional, and does a denial roll back? |
docs/07 |
Demo7DeniedHandling |
What is actually thrown, and how do @HandleAuthorizationDenied and @AuthorizeReturnObject change it? |
docs/06 |
Demo8MetaAnnotations |
Do {value} templates need a bean? What does a method-level rule do to a class-level one? |
docs/08 |
Demo9ParameterNames |
The same class compiled with and without -parameters |
docs/02 |
MethodSecurityTrapsTest |
14 assertions pinning every claim above | docs/09 |
Captured output
| File | From |
|---|---|
docs/output/demo1.txt … demo8.txt |
the eight demos above |
docs/output/demo9-with-parameters.txt |
Demo 9, compiled with -parameters |
docs/output/demo9-without-parameters.txt |
Demo 9, same source, compiled without it |
docs/output/tests.txt |
mvn test |
Regenerate all of it with scripts/run-all.sh. Nothing in docs/ or in the article is
hand-typed output.
Documentation corrections found while building this
Each of these disagrees with the current reference documentation or with widely repeated guidance, and each was verified by running the code or reading the 7.1.1 source:
@EnableMethodSecurityhas anoffsetattribute, notorder.AuthorizationProxyFactoryis inorg.springframework.security.authorization, not…authorization.method.AbstractSecurityExpressionHandler.setRoleHierarchy(..)is deprecated in 7.1;AuthorizationManagerFactoryis where role hierarchy and role prefix now live.{value}meta-annotation templates work without anAnnotationTemplateExpressionDefaultsbean.- Conflicting
@PreAuthorizeinherited from two interfaces fails at call time, not at startup. @PreFilteron an immutable collection is a silent no-op, not an exception.- Package-private methods are advised by a CGLIB proxy.
See docs/09 for the full index.
License
MIT — see LICENSE.