Merge remote-tracking branch 'origin/5.8.x' into main
This commit is contained in:
@@ -38,10 +38,15 @@ public class MockMethodInvocation implements MethodInvocation {
|
||||
|
||||
public MockMethodInvocation(Object targetObject, Class clazz, String methodName, Class... parameterTypes)
|
||||
throws NoSuchMethodException {
|
||||
this.method = clazz.getMethod(methodName, parameterTypes);
|
||||
this(targetObject, clazz.getMethod(methodName, parameterTypes));
|
||||
this.targetObject = targetObject;
|
||||
}
|
||||
|
||||
public MockMethodInvocation(Object targetObject, Method method) {
|
||||
this.targetObject = targetObject;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getArguments() {
|
||||
return this.arguments;
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.aopalliance.intercept.MethodInvocation;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
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;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationManagerAfterReactiveMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class AuthorizationManagerAfterReactiveMethodInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void instantiateWhenPointcutNullThenException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerAfterReactiveMethodInterceptor(null,
|
||||
mock(ReactiveAuthorizationManager.class)))
|
||||
.withMessage("pointcut cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void instantiateWhenAuthorizationManagerNullThenException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerAfterReactiveMethodInterceptor(mock(Pointcut.class), null))
|
||||
.withMessage("authorizationManager cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeMonoWhenMockReactiveAuthorizationManagerThenVerify() throws Throwable {
|
||||
MethodInvocation mockMethodInvocation = spy(
|
||||
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
|
||||
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
|
||||
ReactiveAuthorizationManager<MethodInvocationResult> mockReactiveAuthorizationManager = mock(
|
||||
ReactiveAuthorizationManager.class);
|
||||
given(mockReactiveAuthorizationManager.verify(any(), any())).willReturn(Mono.empty());
|
||||
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(
|
||||
Pointcut.TRUE, mockReactiveAuthorizationManager);
|
||||
Object result = interceptor.invoke(mockMethodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.type(Mono.class)).extracting(Mono::block)
|
||||
.isEqualTo("john");
|
||||
verify(mockReactiveAuthorizationManager).verify(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeFluxWhenMockReactiveAuthorizationManagerThenVerify() throws Throwable {
|
||||
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);
|
||||
given(mockReactiveAuthorizationManager.verify(any(), any())).willReturn(Mono.empty());
|
||||
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(
|
||||
Pointcut.TRUE, mockReactiveAuthorizationManager);
|
||||
Object result = interceptor.invoke(mockMethodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.type(Flux.class)).extracting(Flux::collectList)
|
||||
.extracting(Mono::block, InstanceOfAssertFactories.list(String.class)).containsExactly("john", "bob");
|
||||
verify(mockReactiveAuthorizationManager, times(2)).verify(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeWhenMockReactiveAuthorizationManagerDeniedThenAccessDeniedException() throws Throwable {
|
||||
MethodInvocation mockMethodInvocation = spy(
|
||||
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
|
||||
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
|
||||
ReactiveAuthorizationManager<MethodInvocationResult> mockReactiveAuthorizationManager = mock(
|
||||
ReactiveAuthorizationManager.class);
|
||||
given(mockReactiveAuthorizationManager.verify(any(), any()))
|
||||
.willReturn(Mono.error(new AccessDeniedException("Access Denied")));
|
||||
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(
|
||||
Pointcut.TRUE, mockReactiveAuthorizationManager);
|
||||
Object result = interceptor.invoke(mockMethodInvocation);
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> assertThat(result)
|
||||
.asInstanceOf(InstanceOfAssertFactories.type(Mono.class)).extracting(Mono::block))
|
||||
.withMessage("Access Denied");
|
||||
verify(mockReactiveAuthorizationManager).verify(any(), any());
|
||||
}
|
||||
|
||||
class Sample {
|
||||
|
||||
Mono<String> mono() {
|
||||
return Mono.just("john");
|
||||
}
|
||||
|
||||
Flux<String> flux() {
|
||||
return Flux.just("john", "bob");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.aopalliance.intercept.MethodInvocation;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
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;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationManagerBeforeReactiveMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class AuthorizationManagerBeforeReactiveMethodInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void instantiateWhenPointcutNullThenException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerBeforeReactiveMethodInterceptor(null,
|
||||
mock(ReactiveAuthorizationManager.class)))
|
||||
.withMessage("pointcut cannot be null");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void instantiateWhenAuthorizationManagerNullThenException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerBeforeReactiveMethodInterceptor(mock(Pointcut.class), null))
|
||||
.withMessage("authorizationManager cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeMonoWhenMockReactiveAuthorizationManagerThenVerify() throws Throwable {
|
||||
MethodInvocation mockMethodInvocation = spy(
|
||||
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
|
||||
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
|
||||
ReactiveAuthorizationManager<MethodInvocation> mockReactiveAuthorizationManager = mock(
|
||||
ReactiveAuthorizationManager.class);
|
||||
given(mockReactiveAuthorizationManager.verify(any(), eq(mockMethodInvocation))).willReturn(Mono.empty());
|
||||
AuthorizationManagerBeforeReactiveMethodInterceptor interceptor = new AuthorizationManagerBeforeReactiveMethodInterceptor(
|
||||
Pointcut.TRUE, mockReactiveAuthorizationManager);
|
||||
Object result = interceptor.invoke(mockMethodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.type(Mono.class)).extracting(Mono::block)
|
||||
.isEqualTo("john");
|
||||
verify(mockReactiveAuthorizationManager).verify(any(), eq(mockMethodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeFluxWhenMockReactiveAuthorizationManagerThenVerify() throws Throwable {
|
||||
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);
|
||||
given(mockReactiveAuthorizationManager.verify(any(), eq(mockMethodInvocation))).willReturn(Mono.empty());
|
||||
AuthorizationManagerBeforeReactiveMethodInterceptor interceptor = new AuthorizationManagerBeforeReactiveMethodInterceptor(
|
||||
Pointcut.TRUE, mockReactiveAuthorizationManager);
|
||||
Object result = interceptor.invoke(mockMethodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.type(Flux.class)).extracting(Flux::collectList)
|
||||
.extracting(Mono::block, InstanceOfAssertFactories.list(String.class)).containsExactly("john", "bob");
|
||||
verify(mockReactiveAuthorizationManager).verify(any(), eq(mockMethodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeWhenMockReactiveAuthorizationManagerDeniedThenAccessDeniedException() throws Throwable {
|
||||
MethodInvocation mockMethodInvocation = spy(
|
||||
new MockMethodInvocation(new Sample(), Sample.class.getDeclaredMethod("mono")));
|
||||
given(mockMethodInvocation.proceed()).willReturn(Mono.just("john"));
|
||||
ReactiveAuthorizationManager<MethodInvocation> mockReactiveAuthorizationManager = mock(
|
||||
ReactiveAuthorizationManager.class);
|
||||
given(mockReactiveAuthorizationManager.verify(any(), eq(mockMethodInvocation)))
|
||||
.willReturn(Mono.error(new AccessDeniedException("Access Denied")));
|
||||
AuthorizationManagerBeforeReactiveMethodInterceptor interceptor = new AuthorizationManagerBeforeReactiveMethodInterceptor(
|
||||
Pointcut.TRUE, mockReactiveAuthorizationManager);
|
||||
Object result = interceptor.invoke(mockMethodInvocation);
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> assertThat(result)
|
||||
.asInstanceOf(InstanceOfAssertFactories.type(Mono.class)).extracting(Mono::block))
|
||||
.withMessage("Access Denied");
|
||||
verify(mockReactiveAuthorizationManager).verify(any(), eq(mockMethodInvocation));
|
||||
}
|
||||
|
||||
class Sample {
|
||||
|
||||
Mono<String> mono() {
|
||||
return Mono.just("john");
|
||||
}
|
||||
|
||||
Flux<String> flux() {
|
||||
return Flux.just("john", "bob");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* 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.
|
||||
@@ -51,7 +51,7 @@ public class PostAuthorizeAuthorizationManagerTests {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
manager.setExpressionHandler(expressionHandler);
|
||||
assertThat(manager).extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
assertThat(manager).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PostAuthorizeReactiveAuthorizationManager}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class PostAuthorizeReactiveAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager(
|
||||
expressionHandler);
|
||||
assertThat(manager).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNullThenException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new PostAuthorizeReactiveAuthorizationManager(null))
|
||||
.withMessage("expressionHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingWhenNoPostAuthorizeAnnotationThenNullDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething", new Class[] {}, new Object[] {});
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
AuthorizationDecision decision = manager.check(ReactiveAuthenticationUtils.getAuthentication(), result).block();
|
||||
assertThat(decision).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingStringWhenArgIsGrantThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString", new Class[] { String.class }, new Object[] { "grant" });
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
AuthorizationDecision decision = manager.check(ReactiveAuthenticationUtils.getAuthentication(), result).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingStringWhenArgIsNotGrantThenDeniedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(ReactiveAuthenticationUtils.getAuthentication(), result).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingListWhenReturnObjectContainsGrantThenGrantedDecision() throws Exception {
|
||||
List<String> list = Arrays.asList("grant", "deny");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingList", new Class[] { List.class }, new Object[] { list });
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, list);
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(ReactiveAuthenticationUtils.getAuthentication(), result).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingListWhenReturnObjectNotContainsGrantThenDeniedDecision() throws Exception {
|
||||
List<String> list = Collections.singletonList("deny");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingList", new Class[] { List.class }, new Object[] { list });
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, list);
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(ReactiveAuthenticationUtils.getAuthentication(), result).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresAdminWhenClassAnnotationsThenMethodAnnotationsTakePrecedence() throws Exception {
|
||||
Mono<Authentication> authentication = Mono
|
||||
.just(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedAdmin");
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, result).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
authentication = Mono.just(new TestingAuthenticationToken("user", "password", "ROLE_ADMIN"));
|
||||
decision = manager.check(authentication, result).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresUserWhenClassAnnotationsThenApplies() throws Exception {
|
||||
Mono<Authentication> authentication = Mono
|
||||
.just(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedUser");
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, result).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
authentication = Mono.just(new TestingAuthenticationToken("user", "password", "ROLE_ADMIN"));
|
||||
decision = manager.check(authentication, result).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
Mono<Authentication> authentication = Mono
|
||||
.just(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
Mono<Authentication> authentication = Mono
|
||||
.just(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "inheritedAnnotations");
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeReactiveAuthorizationManager manager = new PostAuthorizeReactiveAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, result));
|
||||
}
|
||||
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
@PostAuthorize("#s == 'grant'")
|
||||
public String doSomethingString(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@PostAuthorize("returnObject.contains('grant')")
|
||||
public List<String> doSomethingList(List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@PostAuthorize("hasRole('USER')")
|
||||
public static class ClassLevelAnnotations implements InterfaceAnnotationsThree {
|
||||
|
||||
@PostAuthorize("hasRole('ADMIN')")
|
||||
public void securedAdmin() {
|
||||
|
||||
}
|
||||
|
||||
public void securedUser() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostAuthorize("hasRole('ADMIN')")
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsOne {
|
||||
|
||||
@PostAuthorize("hasRole('ADMIN')")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsTwo {
|
||||
|
||||
@PostAuthorize("hasRole('USER')")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsThree {
|
||||
|
||||
@MyPostAuthorize
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PostAuthorize("hasRole('USER')")
|
||||
public @interface MyPostAuthorize {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class PostFilterAuthorizationMethodInterceptorTests {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
|
||||
advice.setExpressionHandler(expressionHandler);
|
||||
assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
assertThat(advice).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PostFilterAuthorizationReactiveMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class PostFilterAuthorizationReactiveMethodInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor(
|
||||
expressionHandler);
|
||||
assertThat(interceptor).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNullThenException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new PostFilterAuthorizationReactiveMethodInterceptor(null))
|
||||
.withMessage("expressionHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasNotPostFilterAnnotationThenNotMatches() throws Exception {
|
||||
PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThat(interceptor.getPointcut().getMethodMatcher()
|
||||
.matches(NoPostFilterClass.class.getMethod("doSomething"), NoPostFilterClass.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasPostFilterAnnotationThenMatches() throws Exception {
|
||||
PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThat(interceptor.getPointcut().getMethodMatcher()
|
||||
.matches(TestClass.class.getMethod("doSomethingFlux", Flux.class), TestClass.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeWhenMonoThenFilteredMono() throws Throwable {
|
||||
Mono<String> mono = Mono.just("bob");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingMono", new Class[] { Mono.class }, new Object[] { mono }) {
|
||||
@Override
|
||||
public Object proceed() {
|
||||
return mono;
|
||||
}
|
||||
};
|
||||
PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
||||
Object result = interceptor.invoke(methodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.type(Mono.class)).extracting(Mono::block).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeWhenFluxThenFilteredFlux() throws Throwable {
|
||||
Flux<String> flux = Flux.just("john", "bob");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingFluxClassLevel", new Class[] { Flux.class }, new Object[] { flux }) {
|
||||
@Override
|
||||
public Object proceed() {
|
||||
return flux;
|
||||
}
|
||||
};
|
||||
PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
||||
Object result = interceptor.invoke(methodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.type(Flux.class)).extracting(Flux::collectList)
|
||||
.extracting(Mono::block, InstanceOfAssertFactories.list(String.class)).containsOnly("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> interceptor.invoke(methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ConflictingAnnotations(),
|
||||
ConflictingAnnotations.class, "inheritedAnnotations");
|
||||
PostFilterAuthorizationReactiveMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> interceptor.invoke(methodInvocation));
|
||||
}
|
||||
|
||||
@PostFilter("filterObject == 'john'")
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
@PostFilter("filterObject == 'john'")
|
||||
public Flux<String> doSomethingFlux(Flux<String> flux) {
|
||||
return flux;
|
||||
}
|
||||
|
||||
public Flux<String> doSomethingFluxClassLevel(Flux<String> flux) {
|
||||
return flux;
|
||||
}
|
||||
|
||||
@PostFilter("filterObject == 'john'")
|
||||
public Mono<String> doSomethingMono(Mono<String> mono) {
|
||||
return mono;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class NoPostFilterClass {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ConflictingAnnotations implements InterfaceAnnotationsThree {
|
||||
|
||||
@Override
|
||||
@PostFilter("filterObject == 'jack'")
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsOne {
|
||||
|
||||
@PostFilter("filterObject == 'jim'")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsTwo {
|
||||
|
||||
@PostFilter("filterObject == 'jane'")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsThree {
|
||||
|
||||
@MyPostFilter
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PostFilter("filterObject == 'john'")
|
||||
public @interface MyPostFilter {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* 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.
|
||||
@@ -49,7 +49,7 @@ public class PreAuthorizeAuthorizationManagerTests {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
manager.setExpressionHandler(expressionHandler);
|
||||
assertThat(manager).extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
assertThat(manager).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PreAuthorizeReactiveAuthorizationManager}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class PreAuthorizeReactiveAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager(
|
||||
expressionHandler);
|
||||
assertThat(manager).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNullThenException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new PreAuthorizeReactiveAuthorizationManager(null))
|
||||
.withMessage("expressionHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingWhenNoPostAuthorizeAnnotationThenNullDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething", new Class[] {}, new Object[] {});
|
||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager
|
||||
.check(ReactiveAuthenticationUtils.getAuthentication(), methodInvocation).block();
|
||||
assertThat(decision).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingStringWhenArgIsGrantThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString", new Class[] { String.class }, new Object[] { "grant" });
|
||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager
|
||||
.check(ReactiveAuthenticationUtils.getAuthentication(), methodInvocation).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingStringWhenArgIsNotGrantThenDeniedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
|
||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager
|
||||
.check(ReactiveAuthenticationUtils.getAuthentication(), methodInvocation).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresAdminWhenClassAnnotationsThenMethodAnnotationsTakePrecedence() throws Exception {
|
||||
Mono<Authentication> authentication = Mono
|
||||
.just(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedAdmin");
|
||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
authentication = Mono.just(new TestingAuthenticationToken("user", "password", "ROLE_ADMIN"));
|
||||
decision = manager.check(authentication, methodInvocation).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresUserWhenClassAnnotationsThenApplies() throws Exception {
|
||||
Mono<Authentication> authentication = Mono
|
||||
.just(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedUser");
|
||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
authentication = Mono.just(new TestingAuthenticationToken("user", "password", "ROLE_ADMIN"));
|
||||
decision = manager.check(authentication, methodInvocation).block();
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
Mono<Authentication> authentication = Mono
|
||||
.just(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
Mono<Authentication> authentication = Mono
|
||||
.just(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "inheritedAnnotations");
|
||||
PreAuthorizeReactiveAuthorizationManager manager = new PreAuthorizeReactiveAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
@PreAuthorize("#s == 'grant'")
|
||||
public String doSomethingString(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
public static class ClassLevelAnnotations implements InterfaceAnnotationsThree {
|
||||
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public void securedAdmin() {
|
||||
|
||||
}
|
||||
|
||||
public void securedUser() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsOne {
|
||||
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsTwo {
|
||||
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsThree {
|
||||
|
||||
@MyPreAuthorize
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
public @interface MyPreAuthorize {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public class PreFilterAuthorizationMethodInterceptorTests {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
advice.setExpressionHandler(expressionHandler);
|
||||
assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
assertThat(advice).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.access.prepost.PreFilter;
|
||||
import org.springframework.security.core.parameters.DefaultSecurityParameterNameDiscoverer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PreFilterAuthorizationReactiveMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class PreFilterAuthorizationReactiveMethodInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor(
|
||||
expressionHandler);
|
||||
assertThat(interceptor).extracting("registry").extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNullThenException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new PreFilterAuthorizationReactiveMethodInterceptor(null))
|
||||
.withMessage("expressionHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setParameterNameDiscovererWhenNotNullThenSetsParameterNameDiscoverer() {
|
||||
ParameterNameDiscoverer parameterNameDiscoverer = new DefaultSecurityParameterNameDiscoverer();
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
interceptor.setParameterNameDiscoverer(parameterNameDiscoverer);
|
||||
assertThat(interceptor).extracting("parameterNameDiscoverer").isEqualTo(parameterNameDiscoverer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setParameterNameDiscovererWhenNullThenException() {
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> interceptor.setParameterNameDiscoverer(null))
|
||||
.withMessage("parameterNameDiscoverer cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasNotPreFilterAnnotationThenNotMatches() throws Exception {
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThat(interceptor.getPointcut().getMethodMatcher().matches(NoPreFilterClass.class.getMethod("doSomething"),
|
||||
NoPreFilterClass.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasPreFilterAnnotationThenMatches() throws Exception {
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThat(interceptor.getPointcut().getMethodMatcher()
|
||||
.matches(TestClass.class.getMethod("doSomethingFluxFilterTargetMatch", Flux.class), TestClass.class))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameProvidedAndNotMatchThenException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingFluxFilterTargetNotMatch", new Class[] { Flux.class }, new Object[] { Flux.empty() });
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> interceptor.invoke(methodInvocation)).withMessage(
|
||||
"Filter target was null, or no argument with name 'filterTargetNotMatch' found in method.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameProvidedAndMatchAndNullThenException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingFluxFilterTargetMatch", new Class[] { Flux.class }, new Object[] { null });
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> interceptor.invoke(methodInvocation))
|
||||
.withMessage("Filter target was null, or no argument with name 'flux' found in method.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndSingleArgMonoThenFiltersMono() throws Throwable {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingMonoFilterTargetNotProvided", new Class[] { Mono.class },
|
||||
new Object[] { Mono.just("bob") }) {
|
||||
@Override
|
||||
public Object proceed() {
|
||||
return getArguments()[0];
|
||||
}
|
||||
};
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
Object result = interceptor.invoke(methodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.type(Mono.class)).extracting(Mono::block).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndSingleArgFluxThenFiltersFlux() throws Throwable {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingFluxFilterTargetNotProvided", new Class[] { Flux.class },
|
||||
new Object[] { Flux.just("john", "bob") }) {
|
||||
@Override
|
||||
public Object proceed() {
|
||||
return getArguments()[0];
|
||||
}
|
||||
};
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
Object result = interceptor.invoke(methodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.type(Flux.class)).extracting(Flux::collectList)
|
||||
.extracting(Mono::block, InstanceOfAssertFactories.list(String.class)).containsOnly("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> interceptor.invoke(methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ConflictingAnnotations(),
|
||||
ConflictingAnnotations.class, "inheritedAnnotations");
|
||||
PreFilterAuthorizationReactiveMethodInterceptor interceptor = new PreFilterAuthorizationReactiveMethodInterceptor();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> interceptor.invoke(methodInvocation));
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
@PreFilter(value = "filterObject == 'john'", filterTarget = "filterTargetNotMatch")
|
||||
public Flux<String> doSomethingFluxFilterTargetNotMatch(Flux<String> flux) {
|
||||
return flux;
|
||||
}
|
||||
|
||||
@PreFilter(value = "filterObject == 'john'", filterTarget = "flux")
|
||||
public Flux<String> doSomethingFluxFilterTargetMatch(Flux<String> flux) {
|
||||
return flux;
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public Flux<String> doSomethingFluxFilterTargetNotProvided(Flux<String> flux) {
|
||||
return flux;
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public Mono<String> doSomethingMonoFilterTargetNotProvided(Mono<String> mono) {
|
||||
return mono;
|
||||
}
|
||||
|
||||
public Flux<String> doSomethingTwoArgsFilterTargetNotProvided(String s, Flux<String> flux) {
|
||||
return flux;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class NoPreFilterClass {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ConflictingAnnotations implements InterfaceAnnotationsThree {
|
||||
|
||||
@Override
|
||||
@PreFilter("filterObject == 'jack'")
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsOne {
|
||||
|
||||
@PreFilter("filterObject == 'jim'")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsTwo {
|
||||
|
||||
@PreFilter("filterObject == 'jane'")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsThree {
|
||||
|
||||
@MyPreFilter
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public @interface MyPreFilter {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user