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
35 lines
2.0 KiB
Plaintext
35 lines
2.0 KiB
Plaintext
==============================================================================
|
|
Demo 7 -- @HandleAuthorizationDenied and @AuthorizeReturnObject
|
|
==============================================================================
|
|
SLF4J(W): No SLF4J providers were found.
|
|
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
|
|
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.
|
|
|
|
The exception type you actually catch
|
|
-------------------------------------
|
|
thrown -> org.springframework.security.authorization.AuthorizationDeniedException
|
|
is AccessDeniedException -> true
|
|
is AuthorizationDeniedException -> true
|
|
carries an AuthorizationResult -> ExpressionAuthorizationDecision granted=false
|
|
|
|
Handlers written against AccessDeniedException still work -- but the
|
|
concrete type carries the AuthorizationResult that explains the denial.
|
|
|
|
@HandleAuthorizationDenied: return something instead of throwing
|
|
----------------------------------------------------------------
|
|
maskedBalance() (alice, no ROLE_FINANCE) ALLOWED -> ***masked***
|
|
maskedList() (alice, no ROLE_FINANCE) ALLOWED -> []
|
|
maskedBalance() (cfo, has ROLE_FINANCE) ALLOWED -> 1,204,993.22
|
|
|
|
@AuthorizeReturnObject: the check moves onto the returned object
|
|
----------------------------------------------------------------
|
|
returned instance -> com.ankurm.methodsec.Demo7DeniedHandling$Customer$$SpringCGLIB$$0
|
|
customer.getName() (no authority needed) ALLOWED -> alice
|
|
customer.getEmail() (needs 'pii:read') DENIED -> AuthorizationDeniedException: Access Denied
|
|
customer.getEmail() (has 'pii:read') ALLOWED -> alice@example.com
|
|
|
|
Same thing without the annotation, via AuthorizationProxyFactory
|
|
----------------------------------------------------------------
|
|
raw.getEmail() (unproxied object) ALLOWED -> alice@example.com
|
|
wrapped.getEmail() (proxied object) DENIED -> AuthorizationDeniedException: Access Denied
|