diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableReactiveMethodSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableReactiveMethodSecurity.java index 24a500a36c..04bb9003e8 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableReactiveMethodSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableReactiveMethodSecurity.java @@ -75,6 +75,6 @@ public @interface EnableReactiveMethodSecurity { * used. * @since 5.8 */ - boolean authorizationManager() default false; + boolean useAuthorizationManager() default false; } diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java index 5ebb4f0944..b2ed2ee22d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveAuthorizationManagerMethodSecurityConfiguration.java @@ -45,17 +45,15 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration { @Role(BeanDefinition.ROLE_INFRASTRUCTURE) PreFilterAuthorizationReactiveMethodInterceptor preFilterInterceptor( MethodSecurityExpressionHandler expressionHandler) { - PreFilterAuthorizationReactiveMethodInterceptor preFilter = new PreFilterAuthorizationReactiveMethodInterceptor(); - preFilter.setExpressionHandler(expressionHandler); - return preFilter; + return new PreFilterAuthorizationReactiveMethodInterceptor(expressionHandler); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorizeInterceptor( MethodSecurityExpressionHandler expressionHandler) { - PreAuthorizeReactiveAuthorizationManager authorizationManager = new PreAuthorizeReactiveAuthorizationManager(); - authorizationManager.setExpressionHandler(expressionHandler); + PreAuthorizeReactiveAuthorizationManager authorizationManager = new PreAuthorizeReactiveAuthorizationManager( + expressionHandler); return AuthorizationManagerBeforeReactiveMethodInterceptor.preAuthorize(authorizationManager); } @@ -63,17 +61,15 @@ final class ReactiveAuthorizationManagerMethodSecurityConfiguration { @Role(BeanDefinition.ROLE_INFRASTRUCTURE) PostFilterAuthorizationReactiveMethodInterceptor postFilterInterceptor( MethodSecurityExpressionHandler expressionHandler) { - PostFilterAuthorizationReactiveMethodInterceptor postFilter = new PostFilterAuthorizationReactiveMethodInterceptor(); - postFilter.setExpressionHandler(expressionHandler); - return postFilter; + return new PostFilterAuthorizationReactiveMethodInterceptor(expressionHandler); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeInterceptor( MethodSecurityExpressionHandler expressionHandler) { - PostAuthorizeReactiveAuthorizationManager authorizationManager = new PostAuthorizeReactiveAuthorizationManager(); - authorizationManager.setExpressionHandler(expressionHandler); + PostAuthorizeReactiveAuthorizationManager authorizationManager = new PostAuthorizeReactiveAuthorizationManager( + expressionHandler); return AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize(authorizationManager); } diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java index fd0d304c35..0b679cb1f8 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecuritySelector.java @@ -44,7 +44,7 @@ class ReactiveMethodSecuritySelector implements ImportSelector { EnableReactiveMethodSecurity annotation = importMetadata.getAnnotations() .get(EnableReactiveMethodSecurity.class).synthesize(); List imports = new ArrayList<>(Arrays.asList(this.autoProxy.selectImports(importMetadata))); - if (annotation.authorizationManager()) { + if (annotation.useAuthorizationManager()) { imports.add(ReactiveAuthorizationManagerMethodSecurityConfiguration.class.getName()); } else { diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/DelegatingReactiveMessageService.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/DelegatingReactiveMessageService.java index dd1d5765e6..dc700c4b31 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/DelegatingReactiveMessageService.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/DelegatingReactiveMessageService.java @@ -112,6 +112,11 @@ public class DelegatingReactiveMessageService implements ReactiveMessageService return flux; } + @PostFilter("filterObject.length > 5") + public Flux fluxPostFilter(Flux flux) { + return flux; + } + @Override public Publisher publisherFindById(long id) { return this.delegate.publisherFindById(id); diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/EnableAuthorizationManagerReactiveMethodSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/EnableAuthorizationManagerReactiveMethodSecurityTests.java index 3f21e1bdfb..4db37b61f6 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/EnableAuthorizationManagerReactiveMethodSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/EnableAuthorizationManagerReactiveMethodSecurityTests.java @@ -42,7 +42,7 @@ import static org.mockito.Mockito.reset; /** * Tests for {@link EnableReactiveMethodSecurity} with the - * {@link EnableReactiveMethodSecurity#authorizationManager()} flag set to true. + * {@link EnableReactiveMethodSecurity#useAuthorizationManager()} flag set to true. * * @author Evgeniy Cheban */ @@ -79,8 +79,7 @@ public class EnableAuthorizationManagerReactiveMethodSecurityTests { .withMessage("The returnType class java.lang.String on public abstract java.lang.String " + "org.springframework.security.config.annotation.method.configuration.ReactiveMessageService" + ".notPublisherPreAuthorizeFindById(long) must return an instance of org.reactivestreams" - + ".Publisher (i.e. Mono / Flux) or the function must be a Kotlin coroutine " - + "function in order to support Reactor Context"); + + ".Publisher (for example, a Mono or Flux) in order to support Reactor Context"); } @Test @@ -340,6 +339,13 @@ public class EnableAuthorizationManagerReactiveMethodSecurityTests { StepVerifier.create(flux).expectNext("harold", "jonathan").expectError(AccessDeniedException.class).verify(); } + @Test + public void fluxPostFilterWhenFilteringThenWorks() { + Flux flux = this.messageService.fluxPostFilter(Flux.just("harold", "jonathan", "michael", "pete", "bo")) + .contextWrite(this.withAdmin); + StepVerifier.create(flux).expectNext("harold", "jonathan", "michael").verifyComplete(); + } + // Publisher tests @Test public void publisherWhenPermitAllThenAopDoesNotSubscribe() { @@ -458,7 +464,7 @@ public class EnableAuthorizationManagerReactiveMethodSecurityTests { return publisher(Flux.just(data)); } - @EnableReactiveMethodSecurity(authorizationManager = true) + @EnableReactiveMethodSecurity(useAuthorizationManager = true) static class Config { ReactiveMessageService delegate = mock(ReactiveMessageService.class); diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMessageService.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMessageService.java index 63ea868cd2..2adf54a395 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMessageService.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMessageService.java @@ -48,6 +48,8 @@ public interface ReactiveMessageService { Flux fluxManyAnnotations(Flux flux); + Flux fluxPostFilter(Flux flux); + Publisher publisherFindById(long id); Publisher publisherPreAuthorizeHasRoleFindById(long id); diff --git a/core/src/main/java/org/springframework/security/access/prepost/PrePostAdviceReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/access/prepost/PrePostAdviceReactiveMethodInterceptor.java index b3ca0d5549..d26014ee6e 100644 --- a/core/src/main/java/org/springframework/security/access/prepost/PrePostAdviceReactiveMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/access/prepost/PrePostAdviceReactiveMethodInterceptor.java @@ -52,7 +52,12 @@ import org.springframework.util.Assert; * @author Rob Winch * @author Eleftheria Stein * @since 5.0 + * @deprecated Use + * {@link org.springframework.security.authorization.method.AuthorizationManagerBeforeReactiveMethodInterceptor} + * or + * {@link org.springframework.security.authorization.method.AuthorizationManagerAfterReactiveMethodInterceptor} */ +@Deprecated public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor { private Authentication anonymous = new AnonymousAuthenticationToken("key", "anonymous", diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAfterReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAfterReactiveMethodInterceptor.java deleted file mode 100644 index ae43393e52..0000000000 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAfterReactiveMethodInterceptor.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.authorization.method; - -import java.lang.reflect.Method; - -import org.aopalliance.aop.Advice; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import org.springframework.aop.Pointcut; -import org.springframework.aop.PointcutAdvisor; -import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.core.Ordered; - -/** - * A {@link MethodInterceptor} that wraps a {@link Mono} or a {@link Flux} using - * deffer call. - * - * @author Evgeniy Cheban - * @since 5.8 - */ -final class AuthorizationAfterReactiveMethodInterceptor - implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { - - private final Pointcut pointcut = AuthorizationMethodPointcuts.forAllAnnotations(); - - private final int order = AuthorizationInterceptorsOrder.LAST.getOrder(); - - @Override - public Object invoke(MethodInvocation mi) throws Throwable { - Method method = mi.getMethod(); - Class returnType = method.getReturnType(); - if (Mono.class.isAssignableFrom(returnType)) { - return Mono.defer(() -> ReactiveMethodInvocationUtils.proceed(mi)); - } - return Flux.defer(() -> ReactiveMethodInvocationUtils.proceed(mi)); - } - - @Override - public Pointcut getPointcut() { - return this.pointcut; - } - - @Override - public Advice getAdvice() { - return this; - } - - @Override - public boolean isPerInstance() { - return true; - } - - @Override - public int getOrder() { - return this.order; - } - -} diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationBeanFactoryPostProcessor.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationBeanFactoryPostProcessor.java deleted file mode 100644 index b622562c63..0000000000 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationBeanFactoryPostProcessor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.authorization.method; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import org.springframework.beans.factory.support.RootBeanDefinition; - -/** - * Adds {@link AuthorizationBeforeReactiveMethodInterceptor} and - * {@link AuthorizationAfterReactiveMethodInterceptor} bean definitions to the - * {@link BeanDefinitionRegistry} if they have not already been added. - * - * @author Evgeniy Cheban - * @since 5.8 - */ -final class AuthorizationBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor { - - private static final String BEFORE_INTERCEPTOR_BEAN_NAME = "org.springframework.security.authorization.method.authorizationBeforeReactiveMethodInterceptor"; - - private static final String AFTER_INTERCEPTOR_BEAN_NAME = "org.springframework.security.authorization.method.authorizationAfterReactiveMethodInterceptor"; - - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { - if (!registry.containsBeanDefinition(BEFORE_INTERCEPTOR_BEAN_NAME)) { - RootBeanDefinition beforeInterceptor = new RootBeanDefinition( - AuthorizationBeforeReactiveMethodInterceptor.class); - beforeInterceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(BEFORE_INTERCEPTOR_BEAN_NAME, beforeInterceptor); - } - if (!registry.containsBeanDefinition(AFTER_INTERCEPTOR_BEAN_NAME)) { - RootBeanDefinition afterInterceptor = new RootBeanDefinition( - AuthorizationAfterReactiveMethodInterceptor.class); - afterInterceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(AFTER_INTERCEPTOR_BEAN_NAME, afterInterceptor); - } - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - } - -} diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationBeforeReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationBeforeReactiveMethodInterceptor.java deleted file mode 100644 index 2462fb782f..0000000000 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationBeforeReactiveMethodInterceptor.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.authorization.method; - -import java.lang.reflect.Method; - -import org.aopalliance.aop.Advice; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.reactivestreams.Publisher; - -import org.springframework.aop.Pointcut; -import org.springframework.aop.PointcutAdvisor; -import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.core.Ordered; -import org.springframework.core.ReactiveAdapter; -import org.springframework.core.ReactiveAdapterRegistry; -import org.springframework.util.Assert; - -/** - * A {@link MethodInterceptor} which validates and transforms the return type for methods - * that return a {@link Publisher}. - * - * @author Evgeniy Cheban - * @since 5.8 - */ -final class AuthorizationBeforeReactiveMethodInterceptor - implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { - - private final Pointcut pointcut = AuthorizationMethodPointcuts.forAllAnnotations(); - - private final int order = AuthorizationInterceptorsOrder.FIRST.getOrder(); - - @Override - public Object invoke(MethodInvocation mi) throws Throwable { - Method method = mi.getMethod(); - Class returnType = method.getReturnType(); - Assert.state(Publisher.class.isAssignableFrom(returnType), - () -> "The returnType " + returnType + " on " + method - + " must return an instance of org.reactivestreams.Publisher " - + "(i.e. Mono / Flux) or the function must be a Kotlin coroutine " - + "function in order to support Reactor Context"); - Publisher publisher = ReactiveMethodInvocationUtils.proceed(mi); - ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(returnType); - return (adapter != null) ? adapter.fromPublisher(publisher) : publisher; - } - - @Override - public Pointcut getPointcut() { - return this.pointcut; - } - - @Override - public Advice getAdvice() { - return this; - } - - @Override - public boolean isPerInstance() { - return true; - } - - @Override - public int getOrder() { - return this.order; - } - -} diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterReactiveMethodInterceptor.java index 91010d85c4..c33c36e8f2 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterReactiveMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterReactiveMethodInterceptor.java @@ -16,6 +16,9 @@ package org.springframework.security.authorization.method; +import java.lang.reflect.Method; +import java.util.function.Function; + import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; @@ -26,10 +29,9 @@ import reactor.core.publisher.Mono; import org.springframework.aop.Pointcut; import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.core.Ordered; +import org.springframework.core.ReactiveAdapter; +import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.authorization.ReactiveAuthorizationManager; import org.springframework.security.core.Authentication; @@ -43,16 +45,14 @@ import org.springframework.util.Assert; * @author Evgeniy Cheban * @since 5.8 */ -public final class AuthorizationManagerAfterReactiveMethodInterceptor implements Ordered, MethodInterceptor, - PointcutAdvisor, AopInfrastructureBean, BeanDefinitionRegistryPostProcessor { - - private final AuthorizationBeanFactoryPostProcessor beanFactoryPostProcessor = new AuthorizationBeanFactoryPostProcessor(); +public final class AuthorizationManagerAfterReactiveMethodInterceptor + implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { private final Pointcut pointcut; private final ReactiveAuthorizationManager authorizationManager; - private int order = AuthorizationInterceptorsOrder.POST_AUTHORIZE.getOrder(); + private int order = AuthorizationInterceptorsOrder.LAST.getOrder(); /** * Creates an instance for the {@link PostAuthorize} annotation. @@ -69,8 +69,10 @@ public final class AuthorizationManagerAfterReactiveMethodInterceptor implements */ public static AuthorizationManagerAfterReactiveMethodInterceptor postAuthorize( ReactiveAuthorizationManager authorizationManager) { - return new AuthorizationManagerAfterReactiveMethodInterceptor( + AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor( AuthorizationMethodPointcuts.forAnnotations(PostAuthorize.class), authorizationManager); + interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE.getOrder()); + return interceptor; } /** @@ -95,13 +97,28 @@ public final class AuthorizationManagerAfterReactiveMethodInterceptor implements */ @Override public Object invoke(MethodInvocation mi) throws Throwable { - Publisher publisher = ReactiveMethodInvocationUtils.proceed(mi); + Method method = mi.getMethod(); + Class type = method.getReturnType(); + Assert.state(Publisher.class.isAssignableFrom(type), + () -> String.format("The returnType %s on %s must return an instance of org.reactivestreams.Publisher " + + "(for example, a Mono or Flux) in order to support Reactor Context", type, method)); Mono authentication = ReactiveAuthenticationUtils.getAuthentication(); - if (publisher instanceof Mono) { - Mono mono = (Mono) publisher; - return mono.flatMap((result) -> postAuthorize(authentication, mi, result)); + Function> postAuthorize = (result) -> postAuthorize(authentication, mi, result); + ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(type); + Publisher publisher = ReactiveMethodInvocationUtils.proceed(mi); + if (isMultiValue(type, adapter)) { + Flux flux = Flux.from(publisher).flatMap(postAuthorize); + return (adapter != null) ? adapter.fromPublisher(flux) : flux; } - return Flux.from(publisher).flatMap((result) -> postAuthorize(authentication, mi, result)); + Mono mono = Mono.from(publisher).flatMap(postAuthorize); + return (adapter != null) ? adapter.fromPublisher(mono) : mono; + } + + private boolean isMultiValue(Class returnType, ReactiveAdapter adapter) { + if (Flux.class.isAssignableFrom(returnType)) { + return true; + } + return adapter == null || adapter.isMultiValue(); } private Mono postAuthorize(Mono authentication, MethodInvocation mi, Object result) { @@ -133,14 +150,4 @@ public final class AuthorizationManagerAfterReactiveMethodInterceptor implements this.order = order; } - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { - this.beanFactoryPostProcessor.postProcessBeanDefinitionRegistry(registry); - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - this.beanFactoryPostProcessor.postProcessBeanFactory(beanFactory); - } - } diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeReactiveMethodInterceptor.java index c0e213cd09..8aedb5ad3b 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeReactiveMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeReactiveMethodInterceptor.java @@ -16,19 +16,21 @@ package org.springframework.security.authorization.method; +import java.lang.reflect.Method; + import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.aop.Pointcut; import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.core.Ordered; +import org.springframework.core.ReactiveAdapter; +import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.authorization.ReactiveAuthorizationManager; import org.springframework.security.core.Authentication; @@ -40,18 +42,17 @@ import org.springframework.util.Assert; * {@link ReactiveAuthorizationManager}. * * @author Evgeniy Cheban + * @author Josh Cummings * @since 5.8 */ -public final class AuthorizationManagerBeforeReactiveMethodInterceptor implements Ordered, MethodInterceptor, - PointcutAdvisor, AopInfrastructureBean, BeanDefinitionRegistryPostProcessor { - - private final AuthorizationBeanFactoryPostProcessor beanFactoryPostProcessor = new AuthorizationBeanFactoryPostProcessor(); +public final class AuthorizationManagerBeforeReactiveMethodInterceptor + implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { private final Pointcut pointcut; private final ReactiveAuthorizationManager authorizationManager; - private int order = AuthorizationInterceptorsOrder.PRE_AUTHORIZE.getOrder(); + private int order = AuthorizationInterceptorsOrder.FIRST.getOrder(); /** * Creates an instance for the {@link PreAuthorize} annotation. @@ -68,8 +69,10 @@ public final class AuthorizationManagerBeforeReactiveMethodInterceptor implement */ public static AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorize( ReactiveAuthorizationManager authorizationManager) { - return new AuthorizationManagerBeforeReactiveMethodInterceptor( + AuthorizationManagerBeforeReactiveMethodInterceptor interceptor = new AuthorizationManagerBeforeReactiveMethodInterceptor( AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class), authorizationManager); + interceptor.setOrder(AuthorizationInterceptorsOrder.PRE_AUTHORIZE.getOrder()); + return interceptor; } /** @@ -94,13 +97,29 @@ public final class AuthorizationManagerBeforeReactiveMethodInterceptor implement */ @Override public Object invoke(MethodInvocation mi) throws Throwable { - Publisher publisher = ReactiveMethodInvocationUtils.proceed(mi); + Method method = mi.getMethod(); + Class type = method.getReturnType(); + Assert.state(Publisher.class.isAssignableFrom(type), + () -> String.format("The returnType %s on %s must return an instance of org.reactivestreams.Publisher " + + "(for example, a Mono or Flux) in order to support Reactor Context", type, method)); Mono authentication = ReactiveAuthenticationUtils.getAuthentication(); + ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(type); Mono preAuthorize = this.authorizationManager.verify(authentication, mi); - if (publisher instanceof Mono) { - return preAuthorize.then((Mono) publisher); + if (isMultiValue(type, adapter)) { + Publisher publisher = Flux.defer(() -> ReactiveMethodInvocationUtils.proceed(mi)); + Flux result = preAuthorize.thenMany(publisher); + return (adapter != null) ? adapter.fromPublisher(result) : result; } - return preAuthorize.thenMany(publisher); + Mono publisher = Mono.defer(() -> ReactiveMethodInvocationUtils.proceed(mi)); + Mono result = preAuthorize.then(publisher); + return (adapter != null) ? adapter.fromPublisher(result) : result; + } + + private boolean isMultiValue(Class returnType, ReactiveAdapter adapter) { + if (Flux.class.isAssignableFrom(returnType)) { + return true; + } + return adapter == null || adapter.isMultiValue(); } @Override @@ -127,14 +146,4 @@ public final class AuthorizationManagerBeforeReactiveMethodInterceptor implement this.order = order; } - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { - this.beanFactoryPostProcessor.postProcessBeanDefinitionRegistry(registry); - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - this.beanFactoryPostProcessor.postProcessBeanFactory(beanFactory); - } - } diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeAuthorizationManager.java index dab71e30c9..0835a45acb 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeAuthorizationManager.java @@ -39,14 +39,14 @@ import org.springframework.security.core.Authentication; */ public final class PostAuthorizeAuthorizationManager implements AuthorizationManager { - private final PostAuthorizeExpressionAttributeRegistry registry = new PostAuthorizeExpressionAttributeRegistry(); + private PostAuthorizeExpressionAttributeRegistry registry = new PostAuthorizeExpressionAttributeRegistry(); /** * Use this the {@link MethodSecurityExpressionHandler}. * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use */ public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - this.registry.setExpressionHandler(expressionHandler); + this.registry = new PostAuthorizeExpressionAttributeRegistry(expressionHandler); } /** diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeExpressionAttributeRegistry.java index 7ea4e3c9c4..dcae9b0d72 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeExpressionAttributeRegistry.java @@ -35,17 +35,21 @@ import org.springframework.util.Assert; */ final class PostAuthorizeExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry { - private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); + private final MethodSecurityExpressionHandler expressionHandler; + + PostAuthorizeExpressionAttributeRegistry() { + this(new DefaultMethodSecurityExpressionHandler()); + } + + PostAuthorizeExpressionAttributeRegistry(MethodSecurityExpressionHandler expressionHandler) { + Assert.notNull(expressionHandler, "expressionHandler cannot be null"); + this.expressionHandler = expressionHandler; + } MethodSecurityExpressionHandler getExpressionHandler() { return this.expressionHandler; } - void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - Assert.notNull(expressionHandler, "expressionHandler cannot be null"); - this.expressionHandler = expressionHandler; - } - @NonNull @Override ExpressionAttribute resolveAttribute(Method method, Class targetClass) { diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManager.java index ad34c3d009..214fa9654e 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManager.java @@ -19,11 +19,13 @@ package org.springframework.security.authorization.method; import org.aopalliance.intercept.MethodInvocation; import reactor.core.publisher.Mono; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.ReactiveAuthorizationManager; import org.springframework.security.core.Authentication; +import org.springframework.util.Assert; /** * A {@link ReactiveAuthorizationManager} which can determine if an {@link Authentication} @@ -36,14 +38,15 @@ import org.springframework.security.core.Authentication; public final class PostAuthorizeReactiveAuthorizationManager implements ReactiveAuthorizationManager { - private final PostAuthorizeExpressionAttributeRegistry registry = new PostAuthorizeExpressionAttributeRegistry(); + private final PostAuthorizeExpressionAttributeRegistry registry; - /** - * Sets the {@link MethodSecurityExpressionHandler}. - * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use - */ - public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - this.registry.setExpressionHandler(expressionHandler); + public PostAuthorizeReactiveAuthorizationManager() { + this(new DefaultMethodSecurityExpressionHandler()); + } + + public PostAuthorizeReactiveAuthorizationManager(MethodSecurityExpressionHandler expressionHandler) { + Assert.notNull(expressionHandler, "expressionHandler cannot be null"); + this.registry = new PostAuthorizeExpressionAttributeRegistry(expressionHandler); } /** diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.java index 8843b4345f..4e58611b6d 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.java @@ -49,7 +49,7 @@ public final class PostFilterAuthorizationMethodInterceptor private Supplier authentication = getAuthentication( SecurityContextHolder.getContextHolderStrategy()); - private final PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry(); + private PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry(); private int order = AuthorizationInterceptorsOrder.POST_FILTER.getOrder(); @@ -68,7 +68,7 @@ public final class PostFilterAuthorizationMethodInterceptor * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use */ public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - this.registry.setExpressionHandler(expressionHandler); + this.registry = new PostFilterExpressionAttributeRegistry(expressionHandler); } /** diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptor.java index 601cb10a2e..759a63dd4a 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptor.java @@ -16,6 +16,8 @@ package org.springframework.security.authorization.method; +import java.lang.reflect.Method; + import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; @@ -26,14 +28,15 @@ import reactor.core.publisher.Mono; import org.springframework.aop.Pointcut; import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.core.Ordered; +import org.springframework.core.ReactiveAdapter; +import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.expression.EvaluationContext; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.access.prepost.PostFilter; +import org.springframework.util.Assert; /** * A {@link MethodInterceptor} which filters the returned object from the @@ -43,14 +46,12 @@ import org.springframework.security.access.prepost.PostFilter; * @author Evgeniy Cheban * @since 5.8 */ -public final class PostFilterAuthorizationReactiveMethodInterceptor implements Ordered, MethodInterceptor, - PointcutAdvisor, AopInfrastructureBean, BeanDefinitionRegistryPostProcessor { +public final class PostFilterAuthorizationReactiveMethodInterceptor + implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { - private final AuthorizationBeanFactoryPostProcessor beanFactoryPostProcessor = new AuthorizationBeanFactoryPostProcessor(); + private final PostFilterExpressionAttributeRegistry registry; - private final PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry(); - - private final Pointcut pointcut; + private final Pointcut pointcut = AuthorizationMethodPointcuts.forAnnotations(PostFilter.class); private int order = AuthorizationInterceptorsOrder.POST_FILTER.getOrder(); @@ -58,15 +59,15 @@ public final class PostFilterAuthorizationReactiveMethodInterceptor implements O * Creates an instance. */ public PostFilterAuthorizationReactiveMethodInterceptor() { - this.pointcut = AuthorizationMethodPointcuts.forAnnotations(PostFilter.class); + this(new DefaultMethodSecurityExpressionHandler()); } /** - * Sets the {@link MethodSecurityExpressionHandler}. - * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use + * Creates an instance. */ - public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - this.registry.setExpressionHandler(expressionHandler); + public PostFilterAuthorizationReactiveMethodInterceptor(MethodSecurityExpressionHandler expressionHandler) { + Assert.notNull(expressionHandler, "expressionHandler cannot be null"); + this.registry = new PostFilterExpressionAttributeRegistry(expressionHandler); } /** @@ -77,25 +78,41 @@ public final class PostFilterAuthorizationReactiveMethodInterceptor implements O */ @Override public Object invoke(MethodInvocation mi) throws Throwable { - Publisher publisher = ReactiveMethodInvocationUtils.proceed(mi); ExpressionAttribute attribute = this.registry.getAttribute(mi); if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) { - return publisher; + return ReactiveMethodInvocationUtils.proceed(mi); } Mono toInvoke = ReactiveAuthenticationUtils.getAuthentication() .map((auth) -> this.registry.getExpressionHandler().createEvaluationContext(auth, mi)); - if (publisher instanceof Mono) { - return toInvoke.flatMap((ctx) -> filterMono((Mono) publisher, ctx, attribute)); + Method method = mi.getMethod(); + Class type = method.getReturnType(); + Assert.state(Publisher.class.isAssignableFrom(type), + () -> String.format("The parameter type %s on %s must be an instance of org.reactivestreams.Publisher " + + "(for example, a Mono or Flux) in order to support Reactor Context", type, method)); + ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(type); + if (isMultiValue(type, adapter)) { + Publisher publisher = Flux.defer(() -> ReactiveMethodInvocationUtils.proceed(mi)); + Flux flux = toInvoke.flatMapMany((ctx) -> filterMultiValue(publisher, ctx, attribute)); + return (adapter != null) ? adapter.fromPublisher(flux) : flux; } - return toInvoke.flatMapMany((ctx) -> filterPublisher(publisher, ctx, attribute)); + Publisher publisher = Mono.defer(() -> ReactiveMethodInvocationUtils.proceed(mi)); + Mono mono = toInvoke.flatMap((ctx) -> filterSingleValue(publisher, ctx, attribute)); + return (adapter != null) ? adapter.fromPublisher(mono) : mono; } - private Mono filterMono(Mono mono, EvaluationContext ctx, ExpressionAttribute attribute) { - return mono.doOnNext((result) -> setFilterObject(ctx, result)) + private boolean isMultiValue(Class returnType, ReactiveAdapter adapter) { + if (Flux.class.isAssignableFrom(returnType)) { + return true; + } + return adapter == null || adapter.isMultiValue(); + } + + private Mono filterSingleValue(Publisher publisher, EvaluationContext ctx, ExpressionAttribute attribute) { + return Mono.from(publisher).doOnNext((result) -> setFilterObject(ctx, result)) .flatMap((result) -> postFilter(ctx, result, attribute)); } - private Flux filterPublisher(Publisher publisher, EvaluationContext ctx, ExpressionAttribute attribute) { + private Flux filterMultiValue(Publisher publisher, EvaluationContext ctx, ExpressionAttribute attribute) { return Flux.from(publisher).doOnNext((result) -> setFilterObject(ctx, result)) .flatMap((result) -> postFilter(ctx, result, attribute)); } @@ -133,14 +150,4 @@ public final class PostFilterAuthorizationReactiveMethodInterceptor implements O this.order = order; } - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { - this.beanFactoryPostProcessor.postProcessBeanDefinitionRegistry(registry); - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - this.beanFactoryPostProcessor.postProcessBeanFactory(beanFactory); - } - } diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostFilterExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/PostFilterExpressionAttributeRegistry.java index 21dff77364..44bc2802ab 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostFilterExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostFilterExpressionAttributeRegistry.java @@ -34,17 +34,21 @@ import org.springframework.util.Assert; */ final class PostFilterExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry { - private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); + private final MethodSecurityExpressionHandler expressionHandler; + + PostFilterExpressionAttributeRegistry() { + this.expressionHandler = new DefaultMethodSecurityExpressionHandler(); + } + + PostFilterExpressionAttributeRegistry(MethodSecurityExpressionHandler expressionHandler) { + Assert.notNull(expressionHandler, "expressionHandler cannot be null"); + this.expressionHandler = expressionHandler; + } MethodSecurityExpressionHandler getExpressionHandler() { return this.expressionHandler; } - void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - Assert.notNull(expressionHandler, "expressionHandler cannot be null"); - this.expressionHandler = expressionHandler; - } - @NonNull @Override ExpressionAttribute resolveAttribute(Method method, Class targetClass) { diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManager.java index 987999dd5c..b58a3a7b7e 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManager.java @@ -39,14 +39,14 @@ import org.springframework.security.core.Authentication; */ public final class PreAuthorizeAuthorizationManager implements AuthorizationManager { - private final PreAuthorizeExpressionAttributeRegistry registry = new PreAuthorizeExpressionAttributeRegistry(); + private PreAuthorizeExpressionAttributeRegistry registry = new PreAuthorizeExpressionAttributeRegistry(); /** * Sets the {@link MethodSecurityExpressionHandler}. * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use */ public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - this.registry.setExpressionHandler(expressionHandler); + this.registry = new PreAuthorizeExpressionAttributeRegistry(expressionHandler); } /** diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeExpressionAttributeRegistry.java index 62bf863cd7..7cced570d1 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeExpressionAttributeRegistry.java @@ -35,7 +35,16 @@ import org.springframework.util.Assert; */ final class PreAuthorizeExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry { - private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); + private final MethodSecurityExpressionHandler expressionHandler; + + PreAuthorizeExpressionAttributeRegistry() { + this.expressionHandler = new DefaultMethodSecurityExpressionHandler(); + } + + PreAuthorizeExpressionAttributeRegistry(MethodSecurityExpressionHandler expressionHandler) { + Assert.notNull(expressionHandler, "expressionHandler cannot be null"); + this.expressionHandler = expressionHandler; + } /** * Returns the {@link MethodSecurityExpressionHandler}. @@ -45,15 +54,6 @@ final class PreAuthorizeExpressionAttributeRegistry extends AbstractExpressionAt return this.expressionHandler; } - /** - * Sets the {@link MethodSecurityExpressionHandler}. - * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use - */ - void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - Assert.notNull(expressionHandler, "expressionHandler cannot be null"); - this.expressionHandler = expressionHandler; - } - @NonNull @Override ExpressionAttribute resolveAttribute(Method method, Class targetClass) { diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManager.java index 7ff923300a..cffdf83235 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManager.java @@ -19,11 +19,13 @@ package org.springframework.security.authorization.method; import org.aopalliance.intercept.MethodInvocation; import reactor.core.publisher.Mono; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.ReactiveAuthorizationManager; import org.springframework.security.core.Authentication; +import org.springframework.util.Assert; /** * A {@link ReactiveAuthorizationManager} which can determine if an {@link Authentication} @@ -35,14 +37,15 @@ import org.springframework.security.core.Authentication; */ public final class PreAuthorizeReactiveAuthorizationManager implements ReactiveAuthorizationManager { - private final PreAuthorizeExpressionAttributeRegistry registry = new PreAuthorizeExpressionAttributeRegistry(); + private final PreAuthorizeExpressionAttributeRegistry registry; - /** - * Sets the {@link MethodSecurityExpressionHandler}. - * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use - */ - public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - this.registry.setExpressionHandler(expressionHandler); + public PreAuthorizeReactiveAuthorizationManager() { + this(new DefaultMethodSecurityExpressionHandler()); + } + + public PreAuthorizeReactiveAuthorizationManager(MethodSecurityExpressionHandler expressionHandler) { + Assert.notNull(expressionHandler, "expressionHandler cannot be null"); + this.registry = new PreAuthorizeExpressionAttributeRegistry(expressionHandler); } /** diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.java index 06d2472cd2..a0a9e30171 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.java @@ -50,7 +50,7 @@ public final class PreFilterAuthorizationMethodInterceptor private Supplier authentication = getAuthentication( SecurityContextHolder.getContextHolderStrategy()); - private final PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry(); + private PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry(); private int order = AuthorizationInterceptorsOrder.PRE_FILTER.getOrder(); @@ -69,7 +69,7 @@ public final class PreFilterAuthorizationMethodInterceptor * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use */ public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - this.registry.setExpressionHandler(expressionHandler); + this.registry = new PreFilterExpressionAttributeRegistry(expressionHandler); } /** diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptor.java index 3746e71fd6..a7af3b037c 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptor.java @@ -29,15 +29,13 @@ import org.springframework.aop.Pointcut; import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.framework.AopInfrastructureBean; import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.core.Ordered; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.ReactiveAdapter; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.access.prepost.PreFilter; @@ -52,12 +50,10 @@ import org.springframework.util.StringUtils; * @author Evgeniy Cheban * @since 5.8 */ -public final class PreFilterAuthorizationReactiveMethodInterceptor implements Ordered, MethodInterceptor, - PointcutAdvisor, AopInfrastructureBean, BeanDefinitionRegistryPostProcessor { +public final class PreFilterAuthorizationReactiveMethodInterceptor + implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { - private final AuthorizationBeanFactoryPostProcessor beanFactoryPostProcessor = new AuthorizationBeanFactoryPostProcessor(); - - private final PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry(); + private final PreFilterExpressionAttributeRegistry registry; private final Pointcut pointcut = AuthorizationMethodPointcuts.forAnnotations(PreFilter.class); @@ -65,12 +61,16 @@ public final class PreFilterAuthorizationReactiveMethodInterceptor implements Or private int order = AuthorizationInterceptorsOrder.PRE_FILTER.getOrder(); + public PreFilterAuthorizationReactiveMethodInterceptor() { + this(new DefaultMethodSecurityExpressionHandler()); + } + /** - * Sets the {@link MethodSecurityExpressionHandler}. - * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use + * Creates an instance. */ - public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - this.registry.setExpressionHandler(expressionHandler); + public PreFilterAuthorizationReactiveMethodInterceptor(MethodSecurityExpressionHandler expressionHandler) { + Assert.notNull(expressionHandler, "expressionHandler cannot be null"); + this.registry = new PreFilterExpressionAttributeRegistry(expressionHandler); } /** @@ -92,23 +92,28 @@ public final class PreFilterAuthorizationReactiveMethodInterceptor implements Or public Object invoke(MethodInvocation mi) throws Throwable { PreFilterExpressionAttributeRegistry.PreFilterExpressionAttribute attribute = this.registry.getAttribute(mi); if (attribute == PreFilterExpressionAttributeRegistry.PreFilterExpressionAttribute.NULL_ATTRIBUTE) { - return ReactiveMethodInvocationUtils.>proceed(mi); + return ReactiveMethodInvocationUtils.proceed(mi); } FilterTarget filterTarget = findFilterTarget(attribute.getFilterTarget(), mi); Mono toInvoke = ReactiveAuthenticationUtils.getAuthentication() .map((auth) -> this.registry.getExpressionHandler().createEvaluationContext(auth, mi)); - if (filterTarget.value instanceof Mono) { - mi.getArguments()[filterTarget.index] = toInvoke - .flatMap((ctx) -> filterMono((Mono) filterTarget.value, attribute.getExpression(), ctx)); - } - else { + Method method = mi.getMethod(); + Class type = filterTarget.value.getClass(); + Assert.state(Publisher.class.isAssignableFrom(type), + () -> String.format("The parameter type %s on %s must be an instance of org.reactivestreams.Publisher " + + "(for example, a Mono or Flux) in order to support Reactor Context", type, method)); + ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(type); + if (isMultiValue(type, adapter)) { Flux result = toInvoke - .flatMapMany((ctx) -> filterPublisher(filterTarget.value, attribute.getExpression(), ctx)); - ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance() - .getAdapter(filterTarget.value.getClass()); + .flatMapMany((ctx) -> filterMultiValue(filterTarget.value, attribute.getExpression(), ctx)); mi.getArguments()[filterTarget.index] = (adapter != null) ? adapter.fromPublisher(result) : result; } - return ReactiveMethodInvocationUtils.>proceed(mi); + else { + Mono result = toInvoke + .flatMap((ctx) -> filterSingleValue(filterTarget.value, attribute.getExpression(), ctx)); + mi.getArguments()[filterTarget.index] = (adapter != null) ? adapter.fromPublisher(result) : result; + } + return ReactiveMethodInvocationUtils.proceed(mi); } private FilterTarget findFilterTarget(String name, MethodInvocation mi) { @@ -143,16 +148,23 @@ public final class PreFilterAuthorizationReactiveMethodInterceptor implements Or return new FilterTarget((Publisher) value, index); } - private Mono filterMono(Mono filterTarget, Expression filterExpression, EvaluationContext ctx) { + private boolean isMultiValue(Class returnType, ReactiveAdapter adapter) { + if (Flux.class.isAssignableFrom(returnType)) { + return true; + } + return adapter == null || adapter.isMultiValue(); + } + + private Mono filterSingleValue(Publisher filterTarget, Expression filterExpression, EvaluationContext ctx) { MethodSecurityExpressionOperations rootObject = (MethodSecurityExpressionOperations) ctx.getRootObject() .getValue(); - return filterTarget.filterWhen((filterObject) -> { + return Mono.from(filterTarget).filterWhen((filterObject) -> { rootObject.setFilterObject(filterObject); return ReactiveExpressionUtils.evaluateAsBoolean(filterExpression, ctx); }); } - private Flux filterPublisher(Publisher filterTarget, Expression filterExpression, EvaluationContext ctx) { + private Flux filterMultiValue(Publisher filterTarget, Expression filterExpression, EvaluationContext ctx) { MethodSecurityExpressionOperations rootObject = (MethodSecurityExpressionOperations) ctx.getRootObject() .getValue(); return Flux.from(filterTarget).filterWhen((filterObject) -> { @@ -185,16 +197,6 @@ public final class PreFilterAuthorizationReactiveMethodInterceptor implements Or this.order = order; } - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { - this.beanFactoryPostProcessor.postProcessBeanDefinitionRegistry(registry); - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - this.beanFactoryPostProcessor.postProcessBeanFactory(beanFactory); - } - private static final class FilterTarget { private final Publisher value; diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreFilterExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/PreFilterExpressionAttributeRegistry.java index 7d5e0befb4..b8b6823380 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreFilterExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreFilterExpressionAttributeRegistry.java @@ -35,17 +35,21 @@ import org.springframework.util.Assert; final class PreFilterExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry { - private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); + private final MethodSecurityExpressionHandler expressionHandler; + + PreFilterExpressionAttributeRegistry() { + this.expressionHandler = new DefaultMethodSecurityExpressionHandler(); + } + + PreFilterExpressionAttributeRegistry(MethodSecurityExpressionHandler expressionHandler) { + Assert.notNull(expressionHandler, "expressionHandler cannot be null"); + this.expressionHandler = expressionHandler; + } MethodSecurityExpressionHandler getExpressionHandler() { return this.expressionHandler; } - void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) { - Assert.notNull(expressionHandler, "expressionHandler cannot be null"); - this.expressionHandler = expressionHandler; - } - @NonNull @Override PreFilterExpressionAttribute resolveAttribute(Method method, Class targetClass) { diff --git a/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterReactiveMethodInterceptorTests.java b/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterReactiveMethodInterceptorTests.java index 5b03baa755..199941872e 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterReactiveMethodInterceptorTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterReactiveMethodInterceptorTests.java @@ -24,6 +24,7 @@ import reactor.core.publisher.Mono; import org.springframework.aop.Pointcut; import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.access.intercept.method.MockMethodInvocation; import org.springframework.security.authorization.ReactiveAuthorizationManager; import static org.assertj.core.api.Assertions.assertThat; @@ -32,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -59,7 +61,8 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests { @Test public void invokeMonoWhenMockReactiveAuthorizationManagerThenVerify() throws Throwable { - MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); + MethodInvocation mockMethodInvocation = spy( + new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono"))); given(mockMethodInvocation.proceed()).willReturn(Mono.just("john")); ReactiveAuthorizationManager mockReactiveAuthorizationManager = mock( ReactiveAuthorizationManager.class); @@ -74,7 +77,8 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests { @Test public void invokeFluxWhenMockReactiveAuthorizationManagerThenVerify() throws Throwable { - MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); + MethodInvocation mockMethodInvocation = spy( + new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("flux"))); given(mockMethodInvocation.proceed()).willReturn(Flux.just("john", "bob")); ReactiveAuthorizationManager mockReactiveAuthorizationManager = mock( ReactiveAuthorizationManager.class); @@ -89,7 +93,8 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests { @Test public void invokeWhenMockReactiveAuthorizationManagerDeniedThenAccessDeniedException() throws Throwable { - MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); + MethodInvocation mockMethodInvocation = spy( + new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono"))); given(mockMethodInvocation.proceed()).willReturn(Mono.just("john")); ReactiveAuthorizationManager mockReactiveAuthorizationManager = mock( ReactiveAuthorizationManager.class); @@ -104,4 +109,16 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests { verify(mockReactiveAuthorizationManager).verify(any(), any()); } + class Sample { + + Mono mono() { + return Mono.just("john"); + } + + Flux flux() { + return Flux.just("john", "bob"); + } + + } + } diff --git a/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeReactiveMethodInterceptorTests.java b/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeReactiveMethodInterceptorTests.java index 2127953685..f63b331138 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeReactiveMethodInterceptorTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeReactiveMethodInterceptorTests.java @@ -24,6 +24,7 @@ import reactor.core.publisher.Mono; import org.springframework.aop.Pointcut; import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.access.intercept.method.MockMethodInvocation; import org.springframework.security.authorization.ReactiveAuthorizationManager; import static org.assertj.core.api.Assertions.assertThat; @@ -33,6 +34,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; /** @@ -60,7 +62,8 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests { @Test public void invokeMonoWhenMockReactiveAuthorizationManagerThenVerify() throws Throwable { - MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); + MethodInvocation mockMethodInvocation = spy( + new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono"))); given(mockMethodInvocation.proceed()).willReturn(Mono.just("john")); ReactiveAuthorizationManager mockReactiveAuthorizationManager = mock( ReactiveAuthorizationManager.class); @@ -75,7 +78,8 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests { @Test public void invokeFluxWhenMockReactiveAuthorizationManagerThenVerify() throws Throwable { - MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); + MethodInvocation mockMethodInvocation = spy( + new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("flux"))); given(mockMethodInvocation.proceed()).willReturn(Flux.just("john", "bob")); ReactiveAuthorizationManager mockReactiveAuthorizationManager = mock( ReactiveAuthorizationManager.class); @@ -90,7 +94,8 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests { @Test public void invokeWhenMockReactiveAuthorizationManagerDeniedThenAccessDeniedException() throws Throwable { - MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); + MethodInvocation mockMethodInvocation = spy( + new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono"))); given(mockMethodInvocation.proceed()).willReturn(Mono.just("john")); ReactiveAuthorizationManager mockReactiveAuthorizationManager = mock( ReactiveAuthorizationManager.class); @@ -105,4 +110,16 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests { verify(mockReactiveAuthorizationManager).verify(any(), eq(mockMethodInvocation)); } + class Sample { + + Mono mono() { + return Mono.just("john"); + } + + Flux flux() { + return Flux.just("john", "bob"); + } + + } + } diff --git a/core/src/test/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManagerTests.java b/core/src/test/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManagerTests.java index d7d8083ccc..61cec711ec 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/PostAuthorizeReactiveAuthorizationManagerTests.java @@ -48,15 +48,14 @@ public class PostAuthorizeReactiveAuthorizationManagerTests { @Test public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() { MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); - PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager(); - manager.setExpressionHandler(expressionHandler); + PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager( + expressionHandler); assertThat(manager).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler); } @Test public void setExpressionHandlerWhenNullThenException() { - PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager(); - assertThatIllegalArgumentException().isThrownBy(() -> manager.setExpressionHandler(null)) + assertThatIllegalArgumentException().isThrownBy(() -> new PostAuthorizeReactiveAuthorizationManager(null)) .withMessage("expressionHandler cannot be null"); } diff --git a/core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptorTests.java b/core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptorTests.java index 000c080c70..fdea2e7e23 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptorTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationReactiveMethodInterceptorTests.java @@ -44,15 +44,15 @@ public class PostFilterAuthorizationReactiveMethodInterceptorTests { @Test public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() { MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); - PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor(); - interceptor.setExpressionHandler(expressionHandler); + PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor( + expressionHandler); assertThat(interceptor).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler); } @Test public void setExpressionHandlerWhenNullThenException() { - PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor(); - assertThatIllegalArgumentException().isThrownBy(() -> interceptor.setExpressionHandler(null)) + assertThatIllegalArgumentException() + .isThrownBy(() -> new PostFilterAuthorizationReactiveMethodInterceptor(null)) .withMessage("expressionHandler cannot be null"); } diff --git a/core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManagerTests.java b/core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManagerTests.java index f4ba70921e..b5273d42b7 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeReactiveAuthorizationManagerTests.java @@ -45,15 +45,14 @@ public class PreAuthorizeReactiveAuthorizationManagerTests { @Test public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() { MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); - PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager(); - manager.setExpressionHandler(expressionHandler); + PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager( + expressionHandler); assertThat(manager).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler); } @Test public void setExpressionHandlerWhenNullThenException() { - PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager(); - assertThatIllegalArgumentException().isThrownBy(() -> manager.setExpressionHandler(null)) + assertThatIllegalArgumentException().isThrownBy(() -> new PreAuthorizeReactiveAuthorizationManager(null)) .withMessage("expressionHandler cannot be null"); } diff --git a/core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptorTests.java b/core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptorTests.java index 65430c4f61..913018842b 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptorTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationReactiveMethodInterceptorTests.java @@ -46,15 +46,14 @@ public class PreFilterAuthorizationReactiveMethodInterceptorTests { @Test public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() { MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); - PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor(); - interceptor.setExpressionHandler(expressionHandler); + PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor( + expressionHandler); assertThat(interceptor).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler); } @Test public void setExpressionHandlerWhenNullThenException() { - PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor(); - assertThatIllegalArgumentException().isThrownBy(() -> interceptor.setExpressionHandler(null)) + assertThatIllegalArgumentException().isThrownBy(() -> new PreFilterAuthorizationReactiveMethodInterceptor(null)) .withMessage("expressionHandler cannot be null"); }