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:
Josh Cummings
2021-04-07 15:33:47 -06:00
parent 84e2e80915
commit 67e5c05a47
72 changed files with 4510 additions and 2342 deletions

View File

@@ -60,4 +60,10 @@ public interface BusinessService extends Serializable {
List<?> methodReturningAList(String userName, String extraParam);
@RequireAdminRole
@RequireUserRole
default void repeatedAnnotations() {
}
}

View File

@@ -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() {
}
}
}

View File

@@ -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 {
}

View File

@@ -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 {
}

View File

@@ -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() {
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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() {
}
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -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";
}
}
}

View File

@@ -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 {
}
}

View File

@@ -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 {
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 {
}
}

View File

@@ -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 {
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 {
}
}

View File

@@ -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 {
}
}