mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-30 16:52:13 +00:00
Polish ReactiveMethodSecurity Support
- Changed annotation property to useAuthorizationManager to match related XML support - Moved support found in bean post-processors back into interceptors directly. This reduces the number of components to maintain and simplifies ongoing support - Added @Deprecated annotation to indicate that applications should use AuthorizationManagerBeforeReactiveMethodInterceptor and AuthorizationManagerAfterReactiveMethodInterceptor instead. While true that the new support does not support coroutines, the existing coroutine support is problematic since it cannot be reliably paired with other method interceptors - Moved expression handler configuration to the constructors - Constrain all method security interceptors to require publisher types - Use ReactiveAdapter to check for single-value types as well Issue gh-9401 Polish
This commit is contained in:
parent
6fd23d2567
commit
e990174c89
@ -75,6 +75,6 @@ public @interface EnableReactiveMethodSecurity {
|
||||
* used.
|
||||
* @since 5.8
|
||||
*/
|
||||
boolean authorizationManager() default false;
|
||||
boolean useAuthorizationManager() default false;
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ class ReactiveMethodSecuritySelector implements ImportSelector {
|
||||
EnableReactiveMethodSecurity annotation = importMetadata.getAnnotations()
|
||||
.get(EnableReactiveMethodSecurity.class).synthesize();
|
||||
List<String> imports = new ArrayList<>(Arrays.asList(this.autoProxy.selectImports(importMetadata)));
|
||||
if (annotation.authorizationManager()) {
|
||||
if (annotation.useAuthorizationManager()) {
|
||||
imports.add(ReactiveAuthorizationManagerMethodSecurityConfiguration.class.getName());
|
||||
}
|
||||
else {
|
||||
|
@ -112,6 +112,11 @@ public class DelegatingReactiveMessageService implements ReactiveMessageService
|
||||
return flux;
|
||||
}
|
||||
|
||||
@PostFilter("filterObject.length > 5")
|
||||
public Flux<String> fluxPostFilter(Flux<String> flux) {
|
||||
return flux;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<String> publisherFindById(long id) {
|
||||
return this.delegate.publisherFindById(id);
|
||||
|
@ -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<String> 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);
|
||||
|
@ -48,6 +48,8 @@ public interface ReactiveMessageService {
|
||||
|
||||
Flux<String> fluxManyAnnotations(Flux<String> flux);
|
||||
|
||||
Flux<String> fluxPostFilter(Flux<String> flux);
|
||||
|
||||
Publisher<String> publisherFindById(long id);
|
||||
|
||||
Publisher<String> publisherPreAuthorizeHasRoleFindById(long id);
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
* <code>deffer</code> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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) {
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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<MethodInvocationResult> 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<MethodInvocationResult> 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> authentication = ReactiveAuthenticationUtils.getAuthentication();
|
||||
if (publisher instanceof Mono<?>) {
|
||||
Mono<?> mono = (Mono<?>) publisher;
|
||||
return mono.flatMap((result) -> postAuthorize(authentication, mi, result));
|
||||
Function<Object, Mono<?>> 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> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<MethodInvocation> 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<MethodInvocation> 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> authentication = ReactiveAuthenticationUtils.getAuthentication();
|
||||
ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(type);
|
||||
Mono<Void> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,14 +39,14 @@ import org.springframework.security.core.Authentication;
|
||||
*/
|
||||
public final class PostAuthorizeAuthorizationManager implements AuthorizationManager<MethodInvocationResult> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,17 +35,21 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
final class PostAuthorizeExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
|
||||
|
||||
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) {
|
||||
|
@ -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<MethodInvocationResult> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,7 +49,7 @@ public final class PostFilterAuthorizationMethodInterceptor
|
||||
private Supplier<Authentication> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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<EvaluationContext> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,17 +34,21 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
final class PostFilterExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
|
||||
|
||||
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) {
|
||||
|
@ -39,14 +39,14 @@ import org.springframework.security.core.Authentication;
|
||||
*/
|
||||
public final class PreAuthorizeAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,16 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
final class PreAuthorizeExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
|
||||
|
||||
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) {
|
||||
|
@ -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<MethodInvocation> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,7 +50,7 @@ public final class PreFilterAuthorizationMethodInterceptor
|
||||
private Supplier<Authentication> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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.<Publisher<?>>proceed(mi);
|
||||
return ReactiveMethodInvocationUtils.proceed(mi);
|
||||
}
|
||||
FilterTarget filterTarget = findFilterTarget(attribute.getFilterTarget(), mi);
|
||||
Mono<EvaluationContext> 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.<Publisher<?>>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;
|
||||
|
@ -35,17 +35,21 @@ import org.springframework.util.Assert;
|
||||
final class PreFilterExpressionAttributeRegistry
|
||||
extends AbstractExpressionAttributeRegistry<PreFilterExpressionAttributeRegistry.PreFilterExpressionAttribute> {
|
||||
|
||||
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) {
|
||||
|
@ -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<MethodInvocationResult> 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<MethodInvocationResult> 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<MethodInvocationResult> mockReactiveAuthorizationManager = mock(
|
||||
ReactiveAuthorizationManager.class);
|
||||
@ -104,4 +109,16 @@ public class AuthorizationManagerAfterReactiveMethodInterceptorTests {
|
||||
verify(mockReactiveAuthorizationManager).verify(any(), any());
|
||||
}
|
||||
|
||||
class Sample {
|
||||
|
||||
Mono<String> mono() {
|
||||
return Mono.just("john");
|
||||
}
|
||||
|
||||
Flux<String> flux() {
|
||||
return Flux.just("john", "bob");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<MethodInvocation> 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<MethodInvocation> 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<MethodInvocation> mockReactiveAuthorizationManager = mock(
|
||||
ReactiveAuthorizationManager.class);
|
||||
@ -105,4 +110,16 @@ public class AuthorizationManagerBeforeReactiveMethodInterceptorTests {
|
||||
verify(mockReactiveAuthorizationManager).verify(any(), eq(mockMethodInvocation));
|
||||
}
|
||||
|
||||
class Sample {
|
||||
|
||||
Mono<String> mono() {
|
||||
return Mono.just("john");
|
||||
}
|
||||
|
||||
Flux<String> flux() {
|
||||
return Flux.just("john", "bob");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user