package com.ankurm.methodsec; import java.lang.reflect.Method; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.core.parameters.P; /** * Demo 9 -- {@code #parameterName} depends on a compiler flag. * *

{@code @PreAuthorize("#owner == authentication.name")} resolves {@code #owner} by looking * up the method's parameter names through a {@code ParameterNameDiscoverer}. Parameter names * survive compilation only when {@code javac} is given {@code -parameters}. Without it the * name is {@code arg0}, {@code #owner} resolves to nothing, and the comparison is false -- * every call is denied. * *

{@code scripts/run-all.sh} compiles this module twice and runs this class from both * builds, so {@code docs/output/demo9-with-parameters.txt} and * {@code docs/output/demo9-without-parameters.txt} are the same code under the two flags. * *

Chapter: * docs/02-spel-reference.md. */ public class Demo9ParameterNames { public static void main(String[] args) throws Exception { Support.banner("Demo 9 -- #parameterName and the -parameters compiler flag"); Method byName = Owned.class.getMethod("byParameterName", String.class); Method byAlias = Owned.class.getMethod("byParameterAlias", String.class); System.out.println(" compiled with -parameters : " + byName.getParameters()[0].isNamePresent()); System.out.println(" byParameterName param[0] : " + byName.getParameters()[0].getName()); System.out.println(" byParameterAlias param[0] : " + byAlias.getParameters()[0].getName() + " (annotated @P(\"o\"))"); try (var ctx = new AnnotationConfigApplicationContext(Config.class)) { Owned owned = ctx.getBean(Owned.class); Support.login("alice", "ROLE_USER"); Support.heading("alice calling with her own name"); Support.attempt("#owner == authentication.name", () -> owned.byParameterName("alice")); Support.attempt("#o == authentication.name (@P(\"o\"))", () -> owned.byParameterAlias("alice")); Support.heading("alice calling with somebody else's name"); Support.attempt("#owner == authentication.name", () -> owned.byParameterName("bob")); Support.attempt("#o == authentication.name (@P(\"o\"))", () -> owned.byParameterAlias("bob")); } finally { Support.logout(); } System.out.println(); System.out.println(" Without -parameters the first expression denies BOTH calls -- it fails"); System.out.println(" closed, which is the good direction, but it fails silently in the sense"); System.out.println(" that nothing tells you the rule is not the rule you wrote. @P(\"o\") does"); System.out.println(" not depend on the flag, because the name is in the class file either way."); } @Configuration @EnableMethodSecurity static class Config { @Bean Owned owned() { return new Owned(); } } public static class Owned { @PreAuthorize("#owner == authentication.name") public String byParameterName(String owner) { return "ok"; } @PreAuthorize("#o == authentication.name") public String byParameterAlias(@P("o") String owner) { return "ok"; } } }