Bug description
Found in version: 5.8.13
Fix required in: 5.8.x (required to enable migration to Spring Security 6).
While migrating from @EnableGlobalMethodSecurity(prePostEnabled = true) to @EnableMethodSecurity we have noticed the
methods annotated with @PostFilter are processed twice by the PostFilterAuthorizationMethodInterceptor.
We use a custom PermissionEvaluator and custom MethodSecurityExpressionHandler to evaluate hasPermission
expressions used with various prePost security annotations, for example:
@PreAuthorize("hasPermission(#id, 'SecuredVO', 'SecuredVO:read')")
@PostFilter("hasPermission(filterObject, 'SecuredVO:read')")
List<SecuredVO> findByScopingId(final long scopingId);
The implementation of the PermissionEvaluator and MethodSecurityExpressionHandler is relatively operationally
expensive and filtered objects are modified in some cases (from custom types) as well as removed from standard array /
collection / stream types (using the DefaultMethodSecurityExpressionHandler). Running the filter twice for each
operation annotated with @PostFilter leads to application errors and also significantly reduces performance.
We need this issue to be fixed in the 5.8.x version to enable us to complete migration steps towards upgrade to
Spring Security 6.
Sample
A minimal sample of the issue is provided in this repository.
Steps to reproduce
The sample repository contains sample code and configuration used to reproduce the issue in a much simplified state from the
original application. The issue can be reproduced simply by running the SecuredServiceTest which results in
a RuntimeException to be thrown stating java.lang.RuntimeException: Collection already filtered.. The components of
the test are:
- The configuration classes in
org.radickins.ssa to component scan and @EnableMethodSecurity
- The minimal custom classes in
org.radickins.ssa.security implementing the PermissionEvaluator
and MethodSecurityExpressionHandler
- An implementation of a secured Service in
org.radickins.ssa.service with a simple API annotated with @PostFilter
Given the SecuredService API that is annotated with @PostFilter is entirely self-contained in a simple
implementation, we expect the result to be filtered only once by the Spring Security framework. The permission evaluator
marks each object that should be filtered as having been filtered, and the expression handler raises an exception if it
detects the filterTarget has already been filtered. If working correctly, the expectation is the test should pass as
filtering only occurs once.
Investigation
I have not attempted to fix the issue, but I believe the cause to be due to the bean registration of
the PostFilterAuthorizationMethodInterceptor bean. The PrePostMethodSecurityConfiguration configuration declares the
postFilterAuthorizationMethodInterceptor
bean as an Advisor type, and as you can see the other interceptors for PreFilter, PreAuthorize,
and PostAuthorize are each declared as MethodInterceptor types.
All of these interceptors are registered again as Advisor beans using
the MethodSecurityAdvisorRegistrar
When the secured proxy is built, methods annotated with @PostFilter are assigned any Advisor beans required to
process the AOP security proxy invocation, and the PostFilterAuthorizationMethodInterceptor is added twice (as shown
in the image below taken from debugging a breakpoint in the CustomExpressionHandler).

I believe the fix is to simply register the PostFilterAuthorizationMethodInterceptor as the MethodInterceptor type
in the PrePostMethodSecurityConfiguration config.
Bug description
Found in version: 5.8.13
Fix required in: 5.8.x (required to enable migration to Spring Security 6).
While migrating from
@EnableGlobalMethodSecurity(prePostEnabled = true)to@EnableMethodSecuritywe have noticed themethods annotated with
@PostFilterare processed twice by thePostFilterAuthorizationMethodInterceptor.We use a custom
PermissionEvaluatorand customMethodSecurityExpressionHandlerto evaluatehasPermissionexpressions used with various prePost security annotations, for example:
The implementation of the
PermissionEvaluatorandMethodSecurityExpressionHandleris relatively operationallyexpensive and filtered objects are modified in some cases (from custom types) as well as removed from standard array /
collection / stream types (using the
DefaultMethodSecurityExpressionHandler). Running the filter twice for eachoperation annotated with
@PostFilterleads to application errors and also significantly reduces performance.We need this issue to be fixed in the 5.8.x version to enable us to complete migration steps towards upgrade to
Spring Security 6.
Sample
A minimal sample of the issue is provided in this repository.
Steps to reproduce
The sample repository contains sample code and configuration used to reproduce the issue in a much simplified state from the
original application. The issue can be reproduced simply by running the
SecuredServiceTestwhich results ina
RuntimeExceptionto be thrown statingjava.lang.RuntimeException: Collection already filtered.. The components ofthe test are:
org.radickins.ssato component scan and@EnableMethodSecurityorg.radickins.ssa.securityimplementing thePermissionEvaluatorand
MethodSecurityExpressionHandlerorg.radickins.ssa.servicewith a simple API annotated with@PostFilterGiven the
SecuredServiceAPI that is annotated with@PostFilteris entirely self-contained in a simpleimplementation, we expect the result to be filtered only once by the Spring Security framework. The permission evaluator
marks each object that should be filtered as having been filtered, and the expression handler raises an exception if it
detects the
filterTargethas already been filtered. If working correctly, the expectation is the test should pass asfiltering only occurs once.
Investigation
I have not attempted to fix the issue, but I believe the cause to be due to the bean registration of
the
PostFilterAuthorizationMethodInterceptorbean. ThePrePostMethodSecurityConfigurationconfiguration declares thepostFilterAuthorizationMethodInterceptor
bean as an
Advisortype, and as you can see the other interceptors forPreFilter,PreAuthorize,and
PostAuthorizeare each declared asMethodInterceptortypes.All of these interceptors are registered again as
Advisorbeans usingthe MethodSecurityAdvisorRegistrar
When the secured proxy is built, methods annotated with
@PostFilterare assigned anyAdvisorbeans required toprocess the AOP security proxy invocation, and the
PostFilterAuthorizationMethodInterceptoris added twice (as shownin the image below taken from debugging a breakpoint in the
CustomExpressionHandler).I believe the fix is to simply register the
PostFilterAuthorizationMethodInterceptoras theMethodInterceptortypein the
PrePostMethodSecurityConfigurationconfig.