Polish AuthorizationManager Method Security
- Removed consolidated pointcut advisor in favor of each interceptor being an advisor. This allows Spring AOP to do more of the heavy lifting of selecting the set of interceptors that applies - Created new method context for after interceptors instead of modifying existing one - Added documentation - Added XML support - Added AuthorizationInterceptorsOrder to simplify interceptor ordering - Adjusted annotation lookup to comply with JSR-250 spec - Adjusted annotation lookup to exhaustively search for duplicate annotations - Separated into three @Configuration classes, one for each set of authorization annotations Issue gh-9289
This commit is contained in:
@@ -60,4 +60,10 @@ public interface BusinessService extends Serializable {
|
||||
|
||||
List<?> methodReturningAList(String userName, String extraParam);
|
||||
|
||||
@RequireAdminRole
|
||||
@RequireUserRole
|
||||
default void repeatedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.access.annotation;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.security.DenyAll;
|
||||
import javax.annotation.security.PermitAll;
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
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.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link Jsr250AuthorizationManager}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class Jsr250AuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void rolePrefixWhenNotSetThenDefaultsToRole() {
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
assertThat(manager).extracting("rolePrefix").isEqualTo("ROLE_");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRolePrefixWhenNullThenException() {
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> manager.setRolePrefix(null))
|
||||
.withMessage("rolePrefix cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRolePrefixWhenNotNullThenSets() {
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
manager.setRolePrefix("CUSTOM_");
|
||||
assertThat(manager).extracting("rolePrefix").isEqualTo("CUSTOM_");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingWhenNoJsr250AnnotationsThenNullDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
assertThat(decision).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkPermitAllRolesAllowedAdminWhenRoleUserThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"permitAllRolesAllowedAdmin");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDenyAllRolesAllowedAdminWhenRoleAdminThenDeniedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"denyAllRolesAllowedAdmin");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin,
|
||||
methodAuthorizationContext);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRolesAllowedUserOrAdminWhenRoleUserThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"rolesAllowedUserOrAdmin");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRolesAllowedUserOrAdminWhenRoleAdminThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"rolesAllowedUserOrAdmin");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin,
|
||||
methodAuthorizationContext);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRolesAllowedUserOrAdminWhenRoleAnonymousThenDeniedDecision() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
|
||||
"ROLE_ANONYMOUS");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"rolesAllowedUserOrAdmin");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodAuthorizationContext);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
@DenyAll
|
||||
@RolesAllowed("ADMIN")
|
||||
public void denyAllRolesAllowedAdmin() {
|
||||
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
@RolesAllowed("ADMIN")
|
||||
public void permitAllRolesAllowedAdmin() {
|
||||
|
||||
}
|
||||
|
||||
@RolesAllowed({ "USER", "ADMIN" })
|
||||
public void rolesAllowedUserOrAdmin() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.access.annotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Secured("ADMIN")
|
||||
public @interface RequireAdminRole {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.access.annotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Secured("USER")
|
||||
public @interface RequireUserRole {
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.access.annotation;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tests for {@link SecuredAuthorizationManager}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class SecuredAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingWhenNoSecuredAnnotationThenNullDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
assertThat(decision).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSecuredUserOrAdminWhenRoleUserThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"securedUserOrAdmin");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSecuredUserOrAdminWhenRoleAdminThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"securedUserOrAdmin");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin,
|
||||
methodAuthorizationContext);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSecuredUserOrAdminWhenRoleAnonymousThenDeniedDecision() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
|
||||
"ROLE_ANONYMOUS");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"securedUserOrAdmin");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
|
||||
TestClass.class);
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodAuthorizationContext);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
@Secured({ "ROLE_USER", "ROLE_ADMIN" })
|
||||
public void securedUserOrAdmin() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.access.intercept.aopalliance;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.access.method.AuthorizationMethodAfterAdvice;
|
||||
import org.springframework.security.access.method.AuthorizationMethodBeforeAdvice;
|
||||
import org.springframework.security.access.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
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.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class AuthorizationMethodInterceptorTests {
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeWhenAuthenticatedThenVerifyAdvicesUsage() throws Throwable {
|
||||
Authentication authentication = TestAuthentication.authenticatedUser();
|
||||
SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString");
|
||||
AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> mockBeforeAdvice = mock(
|
||||
AuthorizationMethodBeforeAdvice.class);
|
||||
AuthorizationMethodAfterAdvice<MethodAuthorizationContext> mockAfterAdvice = mock(
|
||||
AuthorizationMethodAfterAdvice.class);
|
||||
given(mockAfterAdvice.after(any(), any(MethodAuthorizationContext.class), eq(null))).willReturn("abc");
|
||||
AuthorizationMethodInterceptor interceptor = new AuthorizationMethodInterceptor(mockBeforeAdvice,
|
||||
mockAfterAdvice);
|
||||
Object result = interceptor.invoke(mockMethodInvocation);
|
||||
assertThat(result).isEqualTo("abc");
|
||||
verify(mockAfterAdvice).after(any(), any(MethodAuthorizationContext.class), eq(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeWhenNotAuthenticatedThenAuthenticationCredentialsNotFoundException() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString");
|
||||
AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> beforeAdvice = new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return MethodMatcher.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before(Supplier<Authentication> authentication,
|
||||
MethodAuthorizationContext methodAuthorizationContext) {
|
||||
authentication.get();
|
||||
}
|
||||
};
|
||||
AuthorizationMethodAfterAdvice<MethodAuthorizationContext> mockAfterAdvice = mock(
|
||||
AuthorizationMethodAfterAdvice.class);
|
||||
AuthorizationMethodInterceptor interceptor = new AuthorizationMethodInterceptor(beforeAdvice, mockAfterAdvice);
|
||||
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
|
||||
.isThrownBy(() -> interceptor.invoke(mockMethodInvocation))
|
||||
.withMessage("An Authentication object was not found in the SecurityContext");
|
||||
verifyNoInteractions(mockAfterAdvice);
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
|
||||
public String doSomethingString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.access.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.support.StaticMethodMatcher;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link DelegatingAuthorizationMethodAfterAdvice}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class DelegatingAuthorizationMethodAfterAdviceTests {
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenNoneMatchesThenNotMatches() throws Exception {
|
||||
List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
|
||||
delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
|
||||
Object returnedObject) {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
|
||||
Object returnedObject) {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
DelegatingAuthorizationMethodAfterAdvice advice = new DelegatingAuthorizationMethodAfterAdvice(delegates);
|
||||
MethodMatcher methodMatcher = advice.getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenAnyMatchesThenMatches() throws Exception {
|
||||
List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
|
||||
delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
|
||||
Object returnedObject) {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
|
||||
Object returnedObject) {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return MethodMatcher.TRUE;
|
||||
}
|
||||
});
|
||||
DelegatingAuthorizationMethodAfterAdvice advice = new DelegatingAuthorizationMethodAfterAdvice(delegates);
|
||||
MethodMatcher methodMatcher = advice.getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenDelegatingAdviceModifiesReturnedObjectThenModifiedReturnedObject() throws Exception {
|
||||
List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
|
||||
delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
|
||||
Object returnedObject) {
|
||||
return returnedObject + "b";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return MethodMatcher.TRUE;
|
||||
}
|
||||
});
|
||||
delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
|
||||
Object returnedObject) {
|
||||
return returnedObject + "c";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return MethodMatcher.TRUE;
|
||||
}
|
||||
});
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
DelegatingAuthorizationMethodAfterAdvice advice = new DelegatingAuthorizationMethodAfterAdvice(delegates);
|
||||
Object result = advice.after(TestAuthentication::authenticatedUser, methodAuthorizationContext, "a");
|
||||
assertThat(result).isEqualTo("abc");
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
|
||||
public String doSomething() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.access.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.support.StaticMethodMatcher;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tests for {@link DelegatingAuthorizationMethodBeforeAdvice}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class DelegatingAuthorizationMethodBeforeAdviceTests {
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenNoneMatchesThenNotMatches() throws Exception {
|
||||
List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
|
||||
delegates.add(new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before(Supplier<Authentication> authentication, MethodAuthorizationContext object) {
|
||||
}
|
||||
});
|
||||
delegates.add(new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before(Supplier<Authentication> authentication, MethodAuthorizationContext object) {
|
||||
}
|
||||
});
|
||||
DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(delegates);
|
||||
MethodMatcher methodMatcher = advice.getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenAnyMatchesThenMatches() throws Exception {
|
||||
List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
|
||||
delegates.add(new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return new StaticMethodMatcher() {
|
||||
@Override
|
||||
public boolean matches(Method method, Class<?> targetClass) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before(Supplier<Authentication> authentication, MethodAuthorizationContext object) {
|
||||
}
|
||||
});
|
||||
delegates.add(new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return MethodMatcher.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before(Supplier<Authentication> authentication, MethodAuthorizationContext object) {
|
||||
}
|
||||
});
|
||||
DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(delegates);
|
||||
MethodMatcher methodMatcher = advice.getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenAllGrantsOrAbstainsThenPasses() throws Exception {
|
||||
List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
|
||||
delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(MethodMatcher.TRUE, (a, o) -> null));
|
||||
delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(MethodMatcher.TRUE,
|
||||
(a, o) -> new AuthorizationDecision(true)));
|
||||
delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(MethodMatcher.TRUE, (a, o) -> null));
|
||||
DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(delegates);
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenAnyDeniesThenAccessDeniedException() throws Exception {
|
||||
List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
|
||||
delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(MethodMatcher.TRUE, (a, o) -> null));
|
||||
delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(MethodMatcher.TRUE,
|
||||
(a, o) -> new AuthorizationDecision(true)));
|
||||
delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(MethodMatcher.TRUE,
|
||||
(a, o) -> new AuthorizationDecision(false)));
|
||||
DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(delegates);
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenDelegatesEmptyThenPasses() throws Exception {
|
||||
DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(
|
||||
Collections.emptyList());
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething");
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext);
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,55 +14,56 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.access.method;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
package org.springframework.security.authorization.method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
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.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationManagerMethodAfterAdvice}.
|
||||
* Tests for {@link AuthorizationManagerAfterMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class AuthorizationManagerMethodAfterAdviceTests {
|
||||
public class AuthorizationManagerAfterMethodInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void instantiateWhenMethodMatcherNullThenException() {
|
||||
AuthorizationManager<MethodInvocationResult> mockAuthorizationManager = mock(AuthorizationManager.class);
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerMethodAfterAdvice<>(null, mock(AuthorizationManager.class)))
|
||||
.withMessage("methodMatcher cannot be null");
|
||||
.isThrownBy(() -> new AuthorizationManagerAfterMethodInterceptor(null, mockAuthorizationManager))
|
||||
.withMessage("pointcut cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void instantiateWhenAuthorizationManagerNullThenException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerMethodAfterAdvice<>(mock(MethodMatcher.class), null))
|
||||
.isThrownBy(() -> new AuthorizationManagerAfterMethodInterceptor(mock(Pointcut.class), null))
|
||||
.withMessage("authorizationManager cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeWhenMockAuthorizationManagerThenVerifyAndReturnedObject() {
|
||||
Supplier<Authentication> authentication = TestAuthentication::authenticatedUser;
|
||||
public void beforeWhenMockAuthorizationManagerThenVerifyAndReturnedObject() throws Throwable {
|
||||
MethodInvocation mockMethodInvocation = mock(MethodInvocation.class);
|
||||
Object returnedObject = new Object();
|
||||
AuthorizationManager<MethodInvocation> mockAuthorizationManager = mock(AuthorizationManager.class);
|
||||
AuthorizationManagerMethodAfterAdvice<MethodInvocation> advice = new AuthorizationManagerMethodAfterAdvice<>(
|
||||
mock(MethodMatcher.class), mockAuthorizationManager);
|
||||
Object result = advice.after(authentication, mockMethodInvocation, returnedObject);
|
||||
assertThat(result).isEqualTo(returnedObject);
|
||||
verify(mockAuthorizationManager).verify(authentication, mockMethodInvocation);
|
||||
MethodInvocationResult result = new MethodInvocationResult(mockMethodInvocation, new Object());
|
||||
given(mockMethodInvocation.proceed()).willReturn(result.getResult());
|
||||
AuthorizationManager<MethodInvocationResult> mockAuthorizationManager = mock(AuthorizationManager.class);
|
||||
AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(
|
||||
Pointcut.TRUE, mockAuthorizationManager);
|
||||
Object returnedObject = advice.invoke(mockMethodInvocation);
|
||||
assertThat(returnedObject).isEqualTo(result.getResult());
|
||||
verify(mockAuthorizationManager).verify(eq(AuthorizationManagerAfterMethodInterceptor.AUTHENTICATION_SUPPLIER),
|
||||
any(MethodInvocationResult.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,52 +14,49 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.access.method;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
package org.springframework.security.authorization.method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationManagerMethodBeforeAdvice}.
|
||||
* Tests for {@link AuthorizationManagerBeforeMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class AuthorizationManagerMethodBeforeAdviceTests {
|
||||
public class AuthorizationManagerBeforeMethodInterceptorTests {
|
||||
|
||||
@Test
|
||||
public void instantiateWhenMethodMatcherNullThenException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerMethodBeforeAdvice<>(null, mock(AuthorizationManager.class)))
|
||||
.withMessage("methodMatcher cannot be null");
|
||||
.isThrownBy(
|
||||
() -> new AuthorizationManagerBeforeMethodInterceptor(null, mock(AuthorizationManager.class)))
|
||||
.withMessage("pointcut cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void instantiateWhenAuthorizationManagerNullThenException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerMethodBeforeAdvice<>(mock(MethodMatcher.class), null))
|
||||
.isThrownBy(() -> new AuthorizationManagerBeforeMethodInterceptor(mock(Pointcut.class), null))
|
||||
.withMessage("authorizationManager cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeWhenMockAuthorizationManagerThenVerify() {
|
||||
Supplier<Authentication> authentication = TestAuthentication::authenticatedUser;
|
||||
public void beforeWhenMockAuthorizationManagerThenVerify() throws Throwable {
|
||||
MethodInvocation mockMethodInvocation = mock(MethodInvocation.class);
|
||||
AuthorizationManager<MethodInvocation> mockAuthorizationManager = mock(AuthorizationManager.class);
|
||||
AuthorizationManagerMethodBeforeAdvice<MethodInvocation> advice = new AuthorizationManagerMethodBeforeAdvice<>(
|
||||
mock(MethodMatcher.class), mockAuthorizationManager);
|
||||
advice.before(authentication, mockMethodInvocation);
|
||||
verify(mockAuthorizationManager).verify(authentication, mockMethodInvocation);
|
||||
AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
|
||||
Pointcut.TRUE, mockAuthorizationManager);
|
||||
advice.invoke(mockMethodInvocation);
|
||||
verify(mockAuthorizationManager).verify(AuthorizationManagerBeforeMethodInterceptor.AUTHENTICATION_SUPPLIER,
|
||||
mockMethodInvocation);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationMethodPointcuts}
|
||||
*/
|
||||
public class AuthorizationMethodPointcutsTests {
|
||||
|
||||
@Test
|
||||
public void forAnnotationsWhenAnnotationThenClassBasedAnnotationPointcut() {
|
||||
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
|
||||
assertThat(AopUtils.canApply(preAuthorize, ClassController.class)).isTrue();
|
||||
assertThat(AopUtils.canApply(preAuthorize, NoController.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forAnnotationsWhenAnnotationThenMethodBasedAnnotationPointcut() {
|
||||
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
|
||||
assertThat(AopUtils.canApply(preAuthorize, MethodController.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forAnnotationsWhenAnnotationThenClassInheritancePointcut() {
|
||||
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
|
||||
assertThat(AopUtils.canApply(preAuthorize, InterfacedClassController.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forAnnotationsWhenAnnotationThenMethodInheritancePointcut() {
|
||||
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
|
||||
assertThat(AopUtils.canApply(preAuthorize, InterfacedMethodController.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forAnnotationsWhenAnnotationThenAnnotationClassInheritancePointcut() {
|
||||
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
|
||||
assertThat(AopUtils.canApply(preAuthorize, InterfacedAnnotationClassController.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forAnnotationsWhenAnnotationThenAnnotationMethodInheritancePointcut() {
|
||||
Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
|
||||
assertThat(AopUtils.canApply(preAuthorize, InterfacedAnnotationMethodController.class)).isTrue();
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('APP')")
|
||||
public static class ClassController {
|
||||
|
||||
String methodOne(String paramOne) {
|
||||
return "value";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class MethodController {
|
||||
|
||||
@PreAuthorize("hasAuthority('APP')")
|
||||
String methodOne(String paramOne) {
|
||||
return "value";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class NoController {
|
||||
|
||||
String methodOne(String paramOne) {
|
||||
return "value";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('APP')")
|
||||
public interface ClassControllerInterface {
|
||||
|
||||
String methodOne(String paramOne);
|
||||
|
||||
}
|
||||
|
||||
public static class InterfacedClassController implements ClassControllerInterface {
|
||||
|
||||
public String methodOne(String paramOne) {
|
||||
return "value";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface MethodControllerInterface {
|
||||
|
||||
@PreAuthorize("hasAuthority('APP')")
|
||||
String methodOne(String paramOne);
|
||||
|
||||
}
|
||||
|
||||
public static class InterfacedMethodController implements MethodControllerInterface {
|
||||
|
||||
public String methodOne(String paramOne) {
|
||||
return "value";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PreAuthorize("hasAuthority('APP')")
|
||||
@interface MyAnnotation {
|
||||
|
||||
}
|
||||
|
||||
@MyAnnotation
|
||||
public interface ClassAnnotationControllerInterface {
|
||||
|
||||
String methodOne(String paramOne);
|
||||
|
||||
}
|
||||
|
||||
public static class InterfacedAnnotationClassController implements ClassAnnotationControllerInterface {
|
||||
|
||||
public String methodOne(String paramOne) {
|
||||
return "value";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface MethodAnnotationControllerInterface {
|
||||
|
||||
@MyAnnotation
|
||||
String methodOne(String paramOne);
|
||||
|
||||
}
|
||||
|
||||
public static class InterfacedAnnotationMethodController implements MethodAnnotationControllerInterface {
|
||||
|
||||
public String methodOne(String paramOne) {
|
||||
return "value";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.function.Supplier;
|
||||
|
||||
import javax.annotation.security.DenyAll;
|
||||
import javax.annotation.security.PermitAll;
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
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 Jsr250AuthorizationManager}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class Jsr250AuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void rolePrefixWhenNotSetThenDefaultsToRole() {
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
assertThat(manager).extracting("rolePrefix").isEqualTo("ROLE_");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRolePrefixWhenNullThenException() {
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> manager.setRolePrefix(null))
|
||||
.withMessage("rolePrefix cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRolePrefixWhenNotNullThenSets() {
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
manager.setRolePrefix("CUSTOM_");
|
||||
assertThat(manager).extracting("rolePrefix").isEqualTo("CUSTOM_");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingWhenNoJsr250AnnotationsThenNullDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
|
||||
assertThat(decision).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkPermitAllWhenRoleUserThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class, "permitAll");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDenyAllWhenRoleAdminThenDeniedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class, "denyAll");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRolesAllowedUserOrAdminWhenRoleUserThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"rolesAllowedUserOrAdmin");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRolesAllowedUserOrAdminWhenRoleAdminThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"rolesAllowedUserOrAdmin");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRolesAllowedUserOrAdminWhenRoleAnonymousThenDeniedDecision() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
|
||||
"ROLE_ANONYMOUS");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"rolesAllowedUserOrAdmin");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkMultipleAnnotationsWhenInvokedThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
|
||||
"ROLE_ANONYMOUS");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"multipleAnnotations");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresAdminWhenClassAnnotationsThenMethodAnnotationsTakePrecedence() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "rolesAllowedAdmin");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_ADMIN");
|
||||
decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDeniedWhenClassAnnotationsThenMethodAnnotationsTakePrecedence() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "denyAll");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresUserWhenClassAnnotationsThenApplies() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "rolesAllowedUser");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_ADMIN");
|
||||
decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "inheritedAnnotations");
|
||||
Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
@DenyAll
|
||||
public void denyAll() {
|
||||
|
||||
}
|
||||
|
||||
@PermitAll
|
||||
public void permitAll() {
|
||||
|
||||
}
|
||||
|
||||
@RolesAllowed({ "USER", "ADMIN" })
|
||||
public void rolesAllowedUserOrAdmin() {
|
||||
|
||||
}
|
||||
|
||||
@RolesAllowed("USER")
|
||||
@DenyAll
|
||||
public void multipleAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RolesAllowed("USER")
|
||||
public static class ClassLevelAnnotations implements InterfaceAnnotationsThree {
|
||||
|
||||
@RolesAllowed("ADMIN")
|
||||
public void rolesAllowedAdmin() {
|
||||
|
||||
}
|
||||
|
||||
@DenyAll
|
||||
public void denyAll() {
|
||||
|
||||
}
|
||||
|
||||
public void rolesAllowedUser() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@PermitAll
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsOne {
|
||||
|
||||
@RolesAllowed("ADMIN")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsTwo {
|
||||
|
||||
@MyRolesAllowed
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsThree {
|
||||
|
||||
@DenyAll
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@RolesAllowed("USER")
|
||||
public @interface MyRolesAllowed {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,21 +16,27 @@
|
||||
|
||||
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 java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
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.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -57,38 +63,32 @@ public class PostAuthorizeAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingWhenNoPostAuthorizeAnnotationThenNullDecision() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething", new Class[] {}, new Object[] {});
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, result);
|
||||
assertThat(decision).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingStringWhenArgIsGrantThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString", new Class[] { String.class }, new Object[] { "grant" });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, result);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingStringWhenArgIsNotGrantThenDeniedDecision() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, result);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
@@ -96,14 +96,11 @@ public class PostAuthorizeAuthorizationManagerTests {
|
||||
@Test
|
||||
public void checkDoSomethingListWhenReturnObjectContainsGrantThenGrantedDecision() throws Exception {
|
||||
List<String> list = Arrays.asList("grant", "deny");
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingList", new Class[] { List.class }, new Object[] { list });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
methodAuthorizationContext.setReturnObject(list);
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, list);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, result);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
@@ -111,19 +108,66 @@ public class PostAuthorizeAuthorizationManagerTests {
|
||||
@Test
|
||||
public void checkDoSomethingListWhenReturnObjectNotContainsGrantThenDeniedDecision() throws Exception {
|
||||
List<String> list = Collections.singletonList("deny");
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingList", new Class[] { List.class }, new Object[] { list });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
methodAuthorizationContext.setReturnObject(list);
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, list);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, result);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
@Test
|
||||
public void checkRequiresAdminWhenClassAnnotationsThenMethodAnnotationsTakePrecedence() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedAdmin");
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, result);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_ADMIN");
|
||||
decision = manager.check(authentication, result);
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresUserWhenClassAnnotationsThenApplies() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedUser");
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, result);
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_ADMIN");
|
||||
decision = manager.check(authentication, result);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, result));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "inheritedAnnotations");
|
||||
MethodInvocationResult result = new MethodInvocationResult(methodInvocation, null);
|
||||
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, result));
|
||||
}
|
||||
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
@@ -139,6 +183,58 @@ public class PostAuthorizeAuthorizationManagerTests {
|
||||
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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
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.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PostFilterAuthorizationMethodAfterAdvice}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class PostFilterAuthorizationMethodAfterAdviceTests {
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice();
|
||||
advice.setExpressionHandler(expressionHandler);
|
||||
assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNullThenException() {
|
||||
PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> advice.setExpressionHandler(null))
|
||||
.withMessage("expressionHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasNotPostFilterAnnotationThenNotMatches() throws Exception {
|
||||
PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice();
|
||||
MethodMatcher methodMatcher = advice.getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasPostFilterAnnotationThenMatches() throws Exception {
|
||||
PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice();
|
||||
MethodMatcher methodMatcher = advice.getMethodMatcher();
|
||||
assertThat(
|
||||
methodMatcher.matches(TestClass.class.getMethod("doSomethingArray", String[].class), TestClass.class))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterWhenArrayNotNullThenFilteredArray() throws Exception {
|
||||
String[] array = { "john", "bob" };
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingArray", new Class[] { String[].class }, new Object[] { array });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice();
|
||||
Object result = advice.after(TestAuthentication::authenticatedUser, methodAuthorizationContext, array);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.array(String[].class)).containsOnly("john");
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
@PostFilter("filterObject == 'john'")
|
||||
public String[] doSomethingArray(String[] array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
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 org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
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 PostFilterAuthorizationMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class PostFilterAuthorizationMethodInterceptorTests {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
SecurityContextHolder.getContext().setAuthentication(TestAuthentication.authenticatedUser());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
|
||||
advice.setExpressionHandler(expressionHandler);
|
||||
assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNullThenException() {
|
||||
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> advice.setExpressionHandler(null))
|
||||
.withMessage("expressionHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasNotPostFilterAnnotationThenNotMatches() throws Exception {
|
||||
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
|
||||
MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(NoPostFilterClass.class.getMethod("doSomething"), NoPostFilterClass.class))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasPostFilterAnnotationThenMatches() throws Exception {
|
||||
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
|
||||
MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
|
||||
assertThat(
|
||||
methodMatcher.matches(TestClass.class.getMethod("doSomethingArray", String[].class), TestClass.class))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterWhenArrayNotNullThenFilteredArray() throws Throwable {
|
||||
String[] array = { "john", "bob" };
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingArrayClassLevel", new Class[] { String[].class }, new Object[] { array }) {
|
||||
@Override
|
||||
public Object proceed() {
|
||||
return array;
|
||||
}
|
||||
};
|
||||
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
|
||||
Object result = advice.invoke(methodInvocation);
|
||||
assertThat(result).asInstanceOf(InstanceOfAssertFactories.array(String[].class)).containsOnly("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> advice.invoke(methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ConflictingAnnotations(),
|
||||
ConflictingAnnotations.class, "inheritedAnnotations");
|
||||
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> advice.invoke(methodInvocation));
|
||||
}
|
||||
|
||||
@PostFilter("filterObject == 'john'")
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
@PostFilter("filterObject == 'john'")
|
||||
public String[] doSomethingArray(String[] array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
public String[] doSomethingArrayClassLevel(String[] array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,17 +16,24 @@
|
||||
|
||||
package org.springframework.security.authorization.method;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
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.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -53,43 +60,80 @@ public class PreAuthorizeAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingWhenNoPostAuthorizeAnnotationThenNullDecision() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething", new Class[] {}, new Object[] {});
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
|
||||
assertThat(decision).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingStringWhenArgIsGrantThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString", new Class[] { String.class }, new Object[] { "grant" });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingStringWhenArgIsNotGrantThenDeniedDecision() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
|
||||
methodAuthorizationContext);
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
@Test
|
||||
public void checkRequiresAdminWhenClassAnnotationsThenMethodAnnotationsTakePrecedence() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedAdmin");
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_ADMIN");
|
||||
decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresUserWhenClassAnnotationsThenApplies() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedUser");
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_ADMIN");
|
||||
decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "inheritedAnnotations");
|
||||
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
@@ -100,6 +144,58 @@ public class PreAuthorizeAuthorizationManagerTests {
|
||||
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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
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.method.MethodAuthorizationContext;
|
||||
import org.springframework.security.access.prepost.PreFilter;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PreFilterAuthorizationMethodBeforeAdvice}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class PreFilterAuthorizationMethodBeforeAdviceTests {
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
advice.setExpressionHandler(expressionHandler);
|
||||
assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNullThenException() {
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> advice.setExpressionHandler(null))
|
||||
.withMessage("expressionHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasNotPreFilterAnnotationThenNotMatches() throws Exception {
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
MethodMatcher methodMatcher = advice.getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasPreFilterAnnotationThenMatches() throws Exception {
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
MethodMatcher methodMatcher = advice.getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomethingListFilterTargetMatch", List.class),
|
||||
TestClass.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameProvidedAndNotMatchThenException() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetNotMatch", new Class[] { List.class }, new Object[] { new ArrayList<>() });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
|
||||
.withMessage(
|
||||
"Filter target was null, or no argument with name 'filterTargetNotMatch' found in method.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameProvidedAndMatchAndNullThenException() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetMatch", new Class[] { List.class }, new Object[] { null });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
|
||||
.withMessage("Filter target was null, or no argument with name 'list' found in method.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameProvidedAndMatchAndNotNullThenFiltersList() throws Exception {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("john");
|
||||
list.add("bob");
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetMatch", new Class[] { List.class }, new Object[] { list });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext);
|
||||
assertThat(list).hasSize(1);
|
||||
assertThat(list.get(0)).isEqualTo("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndSingleArgListNullThenException() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetNotProvided", new Class[] { List.class }, new Object[] { null });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
|
||||
.withMessage("Filter target was null. Make sure you passing the correct value in the method argument.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndSingleArgListThenFiltersList() throws Exception {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("john");
|
||||
list.add("bob");
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetNotProvided", new Class[] { List.class }, new Object[] { list });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext);
|
||||
assertThat(list).hasSize(1);
|
||||
assertThat(list.get(0)).isEqualTo("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndSingleArgArrayThenException() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingArrayFilterTargetNotProvided", new Class[] { String[].class },
|
||||
new Object[] { new String[] {} });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
|
||||
.withMessage(
|
||||
"Pre-filtering on array types is not supported. Using a Collection will solve this problem.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndNotSingleArgThenException() throws Exception {
|
||||
MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingTwoArgsFilterTargetNotProvided", new Class[] { String.class, List.class },
|
||||
new Object[] { "", new ArrayList<>() });
|
||||
MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
|
||||
TestClass.class);
|
||||
PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice();
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
|
||||
.withMessage("Unable to determine the method argument for filtering. Specify the filter target.");
|
||||
}
|
||||
|
||||
public static class TestClass {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
@PreFilter(value = "filterObject == 'john'", filterTarget = "filterTargetNotMatch")
|
||||
public List<String> doSomethingListFilterTargetNotMatch(List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
@PreFilter(value = "filterObject == 'john'", filterTarget = "list")
|
||||
public List<String> doSomethingListFilterTargetMatch(List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public List<String> doSomethingListFilterTargetNotProvided(List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public String[] doSomethingArrayFilterTargetNotProvided(String[] array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public List<String> doSomethingTwoArgsFilterTargetNotProvided(String s, List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
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.authentication.TestAuthentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
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.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PreFilterAuthorizationMethodInterceptor}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class PreFilterAuthorizationMethodInterceptorTests {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
SecurityContextHolder.getContext().setAuthentication(TestAuthentication.authenticatedUser());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
|
||||
MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
advice.setExpressionHandler(expressionHandler);
|
||||
assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setExpressionHandlerWhenNullThenException() {
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> advice.setExpressionHandler(null))
|
||||
.withMessage("expressionHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasNotPreFilterAnnotationThenNotMatches() throws Exception {
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(NoPreFilterClass.class.getMethod("doSomething"), NoPreFilterClass.class))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodMatcherWhenMethodHasPreFilterAnnotationThenMatches() throws Exception {
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
|
||||
assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomethingListFilterTargetMatch", List.class),
|
||||
TestClass.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameProvidedAndNotMatchThenException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetNotMatch", new Class[] { List.class }, new Object[] { new ArrayList<>() });
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> advice.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,
|
||||
"doSomethingListFilterTargetMatch", new Class[] { List.class }, new Object[] { null });
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> advice.invoke(methodInvocation))
|
||||
.withMessage("Filter target was null, or no argument with name 'list' found in method.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameProvidedAndMatchAndNotNullThenFiltersList() throws Throwable {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("john");
|
||||
list.add("bob");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetMatch", new Class[] { List.class }, new Object[] { list });
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
advice.invoke(methodInvocation);
|
||||
assertThat(list).hasSize(1);
|
||||
assertThat(list.get(0)).isEqualTo("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndSingleArgListNullThenException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetNotProvided", new Class[] { List.class }, new Object[] { null });
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> advice.invoke(methodInvocation))
|
||||
.withMessage("Filter target was null. Make sure you passing the correct value in the method argument.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndSingleArgListThenFiltersList() throws Throwable {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("john");
|
||||
list.add("bob");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingListFilterTargetNotProvided", new Class[] { List.class }, new Object[] { list });
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
advice.invoke(methodInvocation);
|
||||
assertThat(list).hasSize(1);
|
||||
assertThat(list.get(0)).isEqualTo("john");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndSingleArgArrayThenException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingArrayFilterTargetNotProvided", new Class[] { String[].class },
|
||||
new Object[] { new String[] {} });
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
assertThatIllegalStateException().isThrownBy(() -> advice.invoke(methodInvocation)).withMessage(
|
||||
"Pre-filtering on array types is not supported. Using a Collection will solve this problem.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFilterTargetWhenNameNotProvidedAndNotSingleArgThenException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomethingTwoArgsFilterTargetNotProvided", new Class[] { String.class, List.class },
|
||||
new Object[] { "", new ArrayList<>() });
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
assertThatIllegalStateException().isThrownBy(() -> advice.invoke(methodInvocation))
|
||||
.withMessage("Unable to determine the method argument for filtering. Specify the filter target.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> advice.invoke(methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ConflictingAnnotations(),
|
||||
ConflictingAnnotations.class, "inheritedAnnotations");
|
||||
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> advice.invoke(methodInvocation));
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
@PreFilter(value = "filterObject == 'john'", filterTarget = "filterTargetNotMatch")
|
||||
public List<String> doSomethingListFilterTargetNotMatch(List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
@PreFilter(value = "filterObject == 'john'", filterTarget = "list")
|
||||
public List<String> doSomethingListFilterTargetMatch(List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public List<String> doSomethingListFilterTargetNotProvided(List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
@PreFilter("filterObject == 'john'")
|
||||
public String[] doSomethingArrayFilterTargetNotProvided(String[] array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
public List<String> doSomethingTwoArgsFilterTargetNotProvided(String s, List<String> list) {
|
||||
return list;
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.access.intercept.method.MockMethodInvocation;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tests for {@link SecuredAuthorizationManager}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
*/
|
||||
public class SecuredAuthorizationManagerTests {
|
||||
|
||||
@Test
|
||||
public void checkDoSomethingWhenNoSecuredAnnotationThenNullDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"doSomething");
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
|
||||
assertThat(decision).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSecuredUserOrAdminWhenRoleUserThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"securedUserOrAdmin");
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSecuredUserOrAdminWhenRoleAdminThenGrantedDecision() throws Exception {
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"securedUserOrAdmin");
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSecuredUserOrAdminWhenRoleAnonymousThenDeniedDecision() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
|
||||
"ROLE_ANONYMOUS");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"securedUserOrAdmin");
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision).isNotNull();
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresAdminWhenClassAnnotationsThenMethodAnnotationsTakePrecedence() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedAdmin");
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_ADMIN");
|
||||
decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequiresUserWhenClassAnnotationsThenApplies() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "securedUser");
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
AuthorizationDecision decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isTrue();
|
||||
authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_ADMIN");
|
||||
decision = manager.check(authentication, methodInvocation);
|
||||
assertThat(decision.isGranted()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenDuplicatedThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
|
||||
"inheritedAnnotations");
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkInheritedAnnotationsWhenConflictingThenAnnotationConfigurationException() throws Exception {
|
||||
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
MockMethodInvocation methodInvocation = new MockMethodInvocation(new ClassLevelAnnotations(),
|
||||
ClassLevelAnnotations.class, "inheritedAnnotations");
|
||||
SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> manager.check(authentication, methodInvocation));
|
||||
}
|
||||
|
||||
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
|
||||
|
||||
public void doSomething() {
|
||||
|
||||
}
|
||||
|
||||
@Secured({ "ROLE_USER", "ROLE_ADMIN" })
|
||||
public void securedUserOrAdmin() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
public static class ClassLevelAnnotations implements InterfaceAnnotationsThree {
|
||||
|
||||
@Secured("ROLE_ADMIN")
|
||||
public void securedAdmin() {
|
||||
|
||||
}
|
||||
|
||||
public void securedUser() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Secured("ROLE_ADMIN")
|
||||
public void inheritedAnnotations() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsOne {
|
||||
|
||||
@Secured("ROLE_ADMIN")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsTwo {
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
public interface InterfaceAnnotationsThree {
|
||||
|
||||
@MySecured
|
||||
void inheritedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Secured("ROLE_USER")
|
||||
public @interface MySecured {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user