Skip to content

Commit 75fd84c

Browse files
committed
Test Reactive Method Security Exactly-One Invocation Semantics
Issue gh-15651
1 parent 1aec571 commit 75fd84c

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostReactiveMethodSecurityConfigurationTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.annotation.Retention;
2020
import java.lang.annotation.RetentionPolicy;
2121
import java.util.ArrayList;
22+
import java.util.Arrays;
2223
import java.util.List;
2324
import java.util.Map;
2425
import java.util.concurrent.ConcurrentHashMap;
@@ -58,6 +59,7 @@
5859
import org.springframework.security.config.Customizer;
5960
import org.springframework.security.config.test.SpringTestContext;
6061
import org.springframework.security.config.test.SpringTestContextExtension;
62+
import org.springframework.security.core.Authentication;
6163
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
6264
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
6365
import org.springframework.security.test.context.support.WithMockUser;
@@ -71,6 +73,7 @@
7173
import static org.mockito.ArgumentMatchers.eq;
7274
import static org.mockito.BDDMockito.given;
7375
import static org.mockito.Mockito.mock;
76+
import static org.mockito.Mockito.spy;
7477
import static org.mockito.Mockito.times;
7578
import static org.mockito.Mockito.verify;
7679

@@ -449,6 +452,20 @@ void autowireWhenAspectJAutoProxyAndFactoryBeanThenExactlyOneAdvisorPerAnnotatio
449452
"postFilterAuthorizationMethodInterceptor", "authorizeReturnObjectMethodInterceptor");
450453
}
451454

455+
// gh-15651
456+
@Test
457+
@WithMockUser(roles = "ADMIN")
458+
public void adviseWhenPrePostEnabledThenEachInterceptorRunsExactlyOnce() {
459+
this.spring
460+
.register(MethodSecurityServiceEnabledConfig.class, CustomMethodSecurityExpressionHandlerConfig.class)
461+
.autowire();
462+
MethodSecurityExpressionHandler expressionHandler = this.spring.getContext()
463+
.getBean(MethodSecurityExpressionHandler.class);
464+
ReactiveMethodSecurityService service = this.spring.getContext().getBean(ReactiveMethodSecurityService.class);
465+
service.manyAnnotations(Mono.just(new ArrayList<>(Arrays.asList("harold", "jonathan", "tim", "bo")))).block();
466+
verify(expressionHandler, times(4)).createEvaluationContext(any(Authentication.class), any());
467+
}
468+
452469
@Configuration
453470
@EnableReactiveMethodSecurity
454471
static class MethodSecurityServiceEnabledConfig {
@@ -460,6 +477,20 @@ ReactiveMethodSecurityService methodSecurityService() {
460477

461478
}
462479

480+
@Configuration
481+
@EnableReactiveMethodSecurity
482+
static class CustomMethodSecurityExpressionHandlerConfig {
483+
484+
private final MethodSecurityExpressionHandler expressionHandler = spy(
485+
new DefaultMethodSecurityExpressionHandler());
486+
487+
@Bean
488+
MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
489+
return this.expressionHandler;
490+
}
491+
492+
}
493+
463494
@Configuration
464495
static class PermissionEvaluatorConfig {
465496

config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityService.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.lang.annotation.Retention;
2222
import java.lang.annotation.RetentionPolicy;
2323
import java.lang.annotation.Target;
24+
import java.util.List;
2425

2526
import org.aopalliance.intercept.MethodInvocation;
2627
import reactor.core.publisher.Mono;
@@ -31,7 +32,9 @@
3132
import org.springframework.expression.Expression;
3233
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
3334
import org.springframework.security.access.prepost.PostAuthorize;
35+
import org.springframework.security.access.prepost.PostFilter;
3436
import org.springframework.security.access.prepost.PreAuthorize;
37+
import org.springframework.security.access.prepost.PreFilter;
3538
import org.springframework.security.authorization.AuthorizationResult;
3639
import org.springframework.security.authorization.method.HandleAuthorizationDenied;
3740
import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler;
@@ -104,6 +107,12 @@ public interface ReactiveMethodSecurityService {
104107
@PreAuthorize("hasPermission(#kgName, 'read')")
105108
Mono<String> preAuthorizeHasPermission(String kgName);
106109

110+
@PreAuthorize("hasRole('ADMIN')")
111+
@PostAuthorize("hasRole('ADMIN')")
112+
@PreFilter("true")
113+
@PostFilter("true")
114+
Mono<List<String>> manyAnnotations(Mono<List<String>> array);
115+
107116
class StarMaskingHandler implements MethodAuthorizationDeniedHandler {
108117

109118
@Override

config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityServiceImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.security.config.annotation.method.configuration;
1818

19+
import java.util.List;
20+
1921
import reactor.core.publisher.Mono;
2022

2123
import org.springframework.security.authorization.AuthorizationDecision;
@@ -93,4 +95,9 @@ public Mono<String> preAuthorizeHasPermission(String kgName) {
9395
return Mono.just("ok");
9496
}
9597

98+
@Override
99+
public Mono<List<String>> manyAnnotations(Mono<List<String>> array) {
100+
return array;
101+
}
102+
96103
}

0 commit comments

Comments
 (0)