package com.ankurm.methodsec; import java.util.ArrayList; import java.util.List; import jakarta.annotation.security.DenyAll; import jakarta.annotation.security.PermitAll; import jakarta.annotation.security.RolesAllowed; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; /** * Demo 1 -- every method-security annotation, on one service, against a real Spring context. * *
The point of this demo is to be boring: it establishes what the happy path looks like so * the later demos can be about the ways it silently does not happen. Chapter: * docs/01-how-method-security-runs.md. * *
Note {@code securedEnabled} and {@code jsr250Enabled} are {@code false} by default on
* {@link EnableMethodSecurity} -- verified by reading the {@code AnnotationDefault} attributes
* out of {@code spring-security-config-7.1.1.jar}, not from prose. {@code @Secured} and
* {@code @RolesAllowed} are therefore inert unless you switch them on, which is silent failure
* number zero.
*/
public class Demo1AnnotationsInAction {
public static void main(String[] args) {
Support.banner("Demo 1 -- the four pre/post annotations, @Secured and JSR-250, all switched on");
try (var ctx = new AnnotationConfigApplicationContext(Config.class)) {
BankService bank = ctx.getBean(BankService.class);
Support.heading("as alice (ROLE_USER)");
Support.login("alice", "ROLE_USER");
Support.attempt("@PreAuthorize hasRole('ADMIN')", () -> bank.adminOnly());
Support.attempt("@PreAuthorize #owner == authentication.name", () -> bank.accountsOf("alice"));
Support.attempt("@PreAuthorize #owner == authentication.name", () -> bank.accountsOf("bob"));
Support.attempt("@PostAuthorize returnObject.owner == ...name", () -> bank.readAccount(1));
Support.attempt("@PostAuthorize returnObject.owner == ...name", () -> bank.readAccount(2));
Support.attempt("@PostFilter filterObject.owner == ...name", () -> bank.allAccounts());
Support.attempt("@Secured(\"ROLE_ADMIN\")", () -> bank.securedAdminOnly());
Support.attempt("@RolesAllowed(\"ADMIN\")", () -> bank.jsr250AdminOnly());
Support.attempt("@PermitAll", () -> bank.jsr250Open());
Support.attempt("@DenyAll", () -> bank.jsr250Closed());
Support.heading("as root (ROLE_ADMIN, ROLE_USER)");
Support.login("root", "ROLE_ADMIN", "ROLE_USER");
Support.attempt("@PreAuthorize hasRole('ADMIN')", () -> bank.adminOnly());
Support.attempt("@Secured(\"ROLE_ADMIN\")", () -> bank.securedAdminOnly());
Support.attempt("@RolesAllowed(\"ADMIN\")", () -> bank.jsr250AdminOnly());
Support.attempt("@PostFilter filterObject.owner == ...name", () -> bank.allAccounts());
Support.heading("with no Authentication at all (SecurityContextHolder cleared)");
Support.logout();
Support.attempt("@PreAuthorize hasRole('ADMIN')", () -> bank.adminOnly());
Support.attempt("@PermitAll", () -> bank.jsr250Open());
Support.heading("@PreFilter -- filtering the ARGUMENT, as alice");
Support.login("alice", "ROLE_USER");
List