Browse Source
- 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 Polishpull/11481/head
30 changed files with 283 additions and 412 deletions
@ -1,76 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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; |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue