mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-01 08:12:14 +00:00
Test Reactive Method Security Exactly-One Invocation Semantics
Issue gh-15651
This commit is contained in:
parent
1aec571a81
commit
75fd84ce16
@ -19,6 +19,7 @@ package org.springframework.security.config.annotation.method.configuration;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -58,6 +59,7 @@ import org.springframework.security.authorization.method.PrePostTemplateDefaults
|
|||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.test.SpringTestContext;
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
|
||||||
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
|
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
|
||||||
import org.springframework.security.test.context.support.WithMockUser;
|
import org.springframework.security.test.context.support.WithMockUser;
|
||||||
@ -71,6 +73,7 @@ import static org.mockito.ArgumentMatchers.any;
|
|||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
@ -449,6 +452,20 @@ public class PrePostReactiveMethodSecurityConfigurationTests {
|
|||||||
"postFilterAuthorizationMethodInterceptor", "authorizeReturnObjectMethodInterceptor");
|
"postFilterAuthorizationMethodInterceptor", "authorizeReturnObjectMethodInterceptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-15651
|
||||||
|
@Test
|
||||||
|
@WithMockUser(roles = "ADMIN")
|
||||||
|
public void adviseWhenPrePostEnabledThenEachInterceptorRunsExactlyOnce() {
|
||||||
|
this.spring
|
||||||
|
.register(MethodSecurityServiceEnabledConfig.class, CustomMethodSecurityExpressionHandlerConfig.class)
|
||||||
|
.autowire();
|
||||||
|
MethodSecurityExpressionHandler expressionHandler = this.spring.getContext()
|
||||||
|
.getBean(MethodSecurityExpressionHandler.class);
|
||||||
|
ReactiveMethodSecurityService service = this.spring.getContext().getBean(ReactiveMethodSecurityService.class);
|
||||||
|
service.manyAnnotations(Mono.just(new ArrayList<>(Arrays.asList("harold", "jonathan", "tim", "bo")))).block();
|
||||||
|
verify(expressionHandler, times(4)).createEvaluationContext(any(Authentication.class), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableReactiveMethodSecurity
|
@EnableReactiveMethodSecurity
|
||||||
static class MethodSecurityServiceEnabledConfig {
|
static class MethodSecurityServiceEnabledConfig {
|
||||||
@ -460,6 +477,20 @@ public class PrePostReactiveMethodSecurityConfigurationTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableReactiveMethodSecurity
|
||||||
|
static class CustomMethodSecurityExpressionHandlerConfig {
|
||||||
|
|
||||||
|
private final MethodSecurityExpressionHandler expressionHandler = spy(
|
||||||
|
new DefaultMethodSecurityExpressionHandler());
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
|
||||||
|
return this.expressionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class PermissionEvaluatorConfig {
|
static class PermissionEvaluatorConfig {
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import java.lang.annotation.Inherited;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
@ -31,7 +32,9 @@ import org.springframework.expression.EvaluationContext;
|
|||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||||
import org.springframework.security.access.prepost.PostAuthorize;
|
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.PreAuthorize;
|
||||||
|
import org.springframework.security.access.prepost.PreFilter;
|
||||||
import org.springframework.security.authorization.AuthorizationResult;
|
import org.springframework.security.authorization.AuthorizationResult;
|
||||||
import org.springframework.security.authorization.method.HandleAuthorizationDenied;
|
import org.springframework.security.authorization.method.HandleAuthorizationDenied;
|
||||||
import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler;
|
import org.springframework.security.authorization.method.MethodAuthorizationDeniedHandler;
|
||||||
@ -104,6 +107,12 @@ public interface ReactiveMethodSecurityService {
|
|||||||
@PreAuthorize("hasPermission(#kgName, 'read')")
|
@PreAuthorize("hasPermission(#kgName, 'read')")
|
||||||
Mono<String> preAuthorizeHasPermission(String kgName);
|
Mono<String> preAuthorizeHasPermission(String kgName);
|
||||||
|
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
@PostAuthorize("hasRole('ADMIN')")
|
||||||
|
@PreFilter("true")
|
||||||
|
@PostFilter("true")
|
||||||
|
Mono<List<String>> manyAnnotations(Mono<List<String>> array);
|
||||||
|
|
||||||
class StarMaskingHandler implements MethodAuthorizationDeniedHandler {
|
class StarMaskingHandler implements MethodAuthorizationDeniedHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
@ -93,4 +95,9 @@ public class ReactiveMethodSecurityServiceImpl implements ReactiveMethodSecurity
|
|||||||
return Mono.just("ok");
|
return Mono.just("ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<List<String>> manyAnnotations(Mono<List<String>> array) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user