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:
@@ -16,12 +16,16 @@
|
||||
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.security.DenyAll;
|
||||
import javax.annotation.security.PermitAll;
|
||||
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.access.prepost.PreFilter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.parameters.P;
|
||||
|
||||
@@ -69,4 +73,15 @@ public interface MethodSecurityService {
|
||||
@PostAuthorize("#o?.contains('grant')")
|
||||
String postAnnotation(@P("o") String object);
|
||||
|
||||
@PreFilter("filterObject.length > 3")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
@Secured("ROLE_USER")
|
||||
@PostFilter("filterObject.length > 5")
|
||||
@PostAuthorize("returnObject.size == 2")
|
||||
List<String> manyAnnotations(List<String> array);
|
||||
|
||||
@RequireUserRole
|
||||
@RequireAdminRole
|
||||
void repeatedAnnotations();
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
@@ -86,4 +88,13 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> manyAnnotations(List<String> object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repeatedAnnotations() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,31 +18,39 @@ package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.aop.support.JdkRegexpMethodPointcut;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.annotation.BusinessService;
|
||||
import org.springframework.security.access.annotation.BusinessServiceImpl;
|
||||
import org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl;
|
||||
import org.springframework.security.access.annotation.Jsr250BusinessServiceImpl;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.method.AuthorizationManagerMethodBeforeAdvice;
|
||||
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.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.authorization.method.AuthorizationInterceptorsOrder;
|
||||
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
|
||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
|
||||
import org.springframework.security.test.context.support.WithAnonymousUser;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
@@ -52,13 +60,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link MethodSecurityConfiguration}.
|
||||
* Tests for {@link PrePostMethodSecurityConfiguration}.
|
||||
*
|
||||
* @author Evgeniy Cheban
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SecurityTestExecutionListeners
|
||||
public class MethodSecurityConfigurationTests {
|
||||
public class PrePostMethodSecurityConfigurationTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
@@ -103,7 +112,7 @@ public class MethodSecurityConfigurationTests {
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void securedWhenRoleUserThenAccessDeniedException() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::secured)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
@@ -119,7 +128,7 @@ public class MethodSecurityConfigurationTests {
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void securedUserWhenRoleAdminThenAccessDeniedException() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::securedUser)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
@@ -147,6 +156,13 @@ public class MethodSecurityConfigurationTests {
|
||||
this.methodSecurityService.preAuthorizeAdmin();
|
||||
}
|
||||
|
||||
@WithMockUser(authorities = "PREFIX_ADMIN")
|
||||
@Test
|
||||
public void preAuthorizeAdminWhenRoleAdminAndCustomPrefixThenPasses() {
|
||||
this.spring.register(CustomGrantedAuthorityDefaultsConfig.class, MethodSecurityServiceConfig.class).autowire();
|
||||
this.methodSecurityService.preAuthorizeAdmin();
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void postHasPermissionWhenParameterIsNotGrantThenAccessDeniedException() {
|
||||
@@ -244,7 +260,7 @@ public class MethodSecurityConfigurationTests {
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void jsr250WhenRoleAdminThenAccessDeniedException() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::jsr250)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
@@ -252,7 +268,7 @@ public class MethodSecurityConfigurationTests {
|
||||
@WithAnonymousUser
|
||||
@Test
|
||||
public void jsr250PermitAllWhenRoleAnonymousThenPasses() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
|
||||
String result = this.methodSecurityService.jsr250PermitAll();
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
@@ -272,7 +288,70 @@ public class MethodSecurityConfigurationTests {
|
||||
this.businessService.rolesAllowedUser();
|
||||
}
|
||||
|
||||
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
|
||||
@WithMockUser(roles = { "ADMIN", "USER" })
|
||||
@Test
|
||||
public void manyAnnotationsWhenMeetsConditionsThenReturnsFilteredList() throws Exception {
|
||||
List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
|
||||
this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
|
||||
List<String> filtered = this.methodSecurityService.manyAnnotations(new ArrayList<>(names));
|
||||
assertThat(filtered).hasSize(2);
|
||||
assertThat(filtered).containsExactly("harold", "jonathan");
|
||||
}
|
||||
|
||||
// gh-4003
|
||||
// gh-4103
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void manyAnnotationsWhenUserThenFails() {
|
||||
List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
|
||||
this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void manyAnnotationsWhenShortListThenFails() {
|
||||
List<String> names = Arrays.asList("harold", "jonathan", "pete");
|
||||
this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
|
||||
}
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void manyAnnotationsWhenAdminThenFails() {
|
||||
List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
|
||||
this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
|
||||
}
|
||||
|
||||
// gh-3183
|
||||
@Test
|
||||
public void repeatedAnnotationsWhenPresentThenFails() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.repeatedAnnotations());
|
||||
}
|
||||
|
||||
// gh-3183
|
||||
@Test
|
||||
public void repeatedJsr250AnnotationsWhenPresentThenFails() {
|
||||
this.spring.register(Jsr250Config.class).autowire();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> this.businessService.repeatedAnnotations());
|
||||
}
|
||||
|
||||
// gh-3183
|
||||
@Test
|
||||
public void repeatedSecuredAnnotationsWhenPresentThenFails() {
|
||||
this.spring.register(SecuredConfig.class).autowire();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> this.businessService.repeatedAnnotations());
|
||||
}
|
||||
|
||||
@EnableMethodSecurity
|
||||
static class MethodSecurityServiceConfig {
|
||||
|
||||
@Bean
|
||||
@@ -292,6 +371,36 @@ public class MethodSecurityConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableMethodSecurity(prePostEnabled = false, securedEnabled = true)
|
||||
static class SecuredConfig {
|
||||
|
||||
@Bean
|
||||
BusinessService businessService() {
|
||||
return new BusinessServiceImpl<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableMethodSecurity(prePostEnabled = false, jsr250Enabled = true)
|
||||
static class Jsr250Config {
|
||||
|
||||
@Bean
|
||||
BusinessService businessService() {
|
||||
return new Jsr250BusinessServiceImpl();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
|
||||
static class MethodSecurityServiceEnabledConfig {
|
||||
|
||||
@Bean
|
||||
MethodSecurityService methodSecurityService() {
|
||||
return new MethodSecurityServiceImpl();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableMethodSecurity
|
||||
static class CustomPermissionEvaluatorConfig {
|
||||
|
||||
@@ -316,16 +425,27 @@ public class MethodSecurityConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableMethodSecurity
|
||||
static class CustomGrantedAuthorityDefaultsConfig {
|
||||
|
||||
@Bean
|
||||
GrantedAuthorityDefaults grantedAuthorityDefaults() {
|
||||
return new GrantedAuthorityDefaults("PREFIX_");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableMethodSecurity
|
||||
static class CustomAuthorizationManagerBeforeAdviceConfig {
|
||||
|
||||
@Bean
|
||||
AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> customBeforeAdvice() {
|
||||
JdkRegexpMethodPointcut methodMatcher = new JdkRegexpMethodPointcut();
|
||||
methodMatcher.setPattern(".*MethodSecurityServiceImpl.*securedUser");
|
||||
AuthorizationManager<MethodAuthorizationContext> authorizationManager = (a,
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
Advisor customBeforeAdvice() {
|
||||
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
|
||||
pointcut.setPattern(".*MethodSecurityServiceImpl.*securedUser");
|
||||
AuthorizationManager<MethodInvocation> authorizationManager = (a,
|
||||
o) -> new AuthorizationDecision("bob".equals(a.get().getName()));
|
||||
return new AuthorizationManagerMethodBeforeAdvice<>(methodMatcher, authorizationManager);
|
||||
return new AuthorizationManagerBeforeMethodInterceptor(pointcut, authorizationManager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -334,25 +454,20 @@ public class MethodSecurityConfigurationTests {
|
||||
static class CustomAuthorizationManagerAfterAdviceConfig {
|
||||
|
||||
@Bean
|
||||
AuthorizationMethodAfterAdvice<MethodAuthorizationContext> customAfterAdvice() {
|
||||
JdkRegexpMethodPointcut methodMatcher = new JdkRegexpMethodPointcut();
|
||||
methodMatcher.setPattern(".*MethodSecurityServiceImpl.*securedUser");
|
||||
return new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
|
||||
@Override
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return methodMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object after(Supplier<Authentication> authentication,
|
||||
MethodAuthorizationContext methodAuthorizationContext, Object returnedObject) {
|
||||
Authentication auth = authentication.get();
|
||||
if ("bob".equals(auth.getName())) {
|
||||
return "granted";
|
||||
}
|
||||
throw new AccessDeniedException("Access Denied for User '" + auth.getName() + "'");
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
Advisor customAfterAdvice() {
|
||||
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
|
||||
pointcut.setPattern(".*MethodSecurityServiceImpl.*securedUser");
|
||||
MethodInterceptor interceptor = (mi) -> {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if ("bob".equals(auth.getName())) {
|
||||
return "granted";
|
||||
}
|
||||
throw new AccessDeniedException("Access Denied for User '" + auth.getName() + "'");
|
||||
};
|
||||
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, interceptor);
|
||||
advisor.setOrder(AuthorizationInterceptorsOrder.POST_FILTER.getOrder() + 1);
|
||||
return advisor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.config.annotation.method.configuration;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public @interface RequireAdminRole {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.config.annotation.method.configuration;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
public @interface RequireUserRole {
|
||||
|
||||
}
|
||||
@@ -52,7 +52,6 @@ public class XsdDocumentedTests {
|
||||
"nsa-authentication",
|
||||
"nsa-websocket-security",
|
||||
"nsa-ldap",
|
||||
"nsa-method-security",
|
||||
"nsa-web",
|
||||
// deprecated and for removal
|
||||
"nsa-frame-options-strategy",
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright 2002-2017 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.config.method;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.annotation.BusinessService;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.config.annotation.method.configuration.MethodSecurityService;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
|
||||
import org.springframework.security.test.context.support.WithAnonymousUser;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SecurityTestExecutionListeners
|
||||
public class MethodSecurityBeanDefinitionParserTests {
|
||||
|
||||
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/method/MethodSecurityBeanDefinitionParserTests";
|
||||
|
||||
private final UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob",
|
||||
"bobspassword");
|
||||
|
||||
@Autowired(required = false)
|
||||
MethodSecurityService methodSecurityService;
|
||||
|
||||
@Autowired(required = false)
|
||||
BusinessService businessService;
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void preAuthorizeWhenRoleAdminThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::preAuthorize)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithAnonymousUser
|
||||
@Test
|
||||
public void preAuthorizePermitAllWhenRoleAnonymousThenPasses() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
String result = this.methodSecurityService.preAuthorizePermitAll();
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@WithAnonymousUser
|
||||
@Test
|
||||
public void preAuthorizeNotAnonymousWhenRoleAnonymousThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(this.methodSecurityService::preAuthorizeNotAnonymous).withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void preAuthorizeNotAnonymousWhenRoleUserThenPasses() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
this.methodSecurityService.preAuthorizeNotAnonymous();
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void securedWhenRoleUserThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabled")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::secured)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void securedWhenRoleAdminThenPasses() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
String result = this.methodSecurityService.secured();
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void securedUserWhenRoleAdminThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabled")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::securedUser)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void securedUserWhenRoleUserThenPasses() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
String result = this.methodSecurityService.securedUser();
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void preAuthorizeAdminWhenRoleUserThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::preAuthorizeAdmin)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void preAuthorizeAdminWhenRoleAdminThenPasses() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
this.methodSecurityService.preAuthorizeAdmin();
|
||||
}
|
||||
|
||||
@WithMockUser(authorities = "PREFIX_ADMIN")
|
||||
@Test
|
||||
public void preAuthorizeAdminWhenRoleAdminAndCustomPrefixThenPasses() {
|
||||
this.spring.configLocations(xml("CustomGrantedAuthorityDefaults")).autowire();
|
||||
this.methodSecurityService.preAuthorizeAdmin();
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void postHasPermissionWhenParameterIsNotGrantThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("CustomPermissionEvaluator")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.postHasPermission("deny")).withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void postHasPermissionWhenParameterIsGrantThenPasses() {
|
||||
this.spring.configLocations(xml("CustomPermissionEvaluator")).autowire();
|
||||
String result = this.methodSecurityService.postHasPermission("grant");
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void postAnnotationWhenParameterIsNotGrantThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.postAnnotation("deny")).withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void postAnnotationWhenParameterIsGrantThenPasses() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
String result = this.methodSecurityService.postAnnotation("grant");
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@WithMockUser("bob")
|
||||
@Test
|
||||
public void methodReturningAListWhenPrePostFiltersConfiguredThenFiltersList() {
|
||||
this.spring.configLocations(xml("BusinessService")).autowire();
|
||||
List<String> names = new ArrayList<>();
|
||||
names.add("bob");
|
||||
names.add("joe");
|
||||
names.add("sam");
|
||||
List<?> result = this.businessService.methodReturningAList(names);
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0)).isEqualTo("bob");
|
||||
}
|
||||
|
||||
@WithMockUser("bob")
|
||||
@Test
|
||||
public void methodReturningAnArrayWhenPostFilterConfiguredThenFiltersArray() {
|
||||
this.spring.configLocations(xml("BusinessService")).autowire();
|
||||
List<String> names = new ArrayList<>();
|
||||
names.add("bob");
|
||||
names.add("joe");
|
||||
names.add("sam");
|
||||
Object[] result = this.businessService.methodReturningAnArray(names.toArray());
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result[0]).isEqualTo("bob");
|
||||
}
|
||||
|
||||
@WithMockUser("bob")
|
||||
@Test
|
||||
public void securedUserWhenCustomBeforeAdviceConfiguredAndNameBobThenPasses() {
|
||||
this.spring.configLocations(xml("CustomAuthorizationManagerBeforeAdvice")).autowire();
|
||||
String result = this.methodSecurityService.securedUser();
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@WithMockUser("joe")
|
||||
@Test
|
||||
public void securedUserWhenCustomBeforeAdviceConfiguredAndNameNotBobThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("CustomAuthorizationManagerBeforeAdvice")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::securedUser)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithMockUser("bob")
|
||||
@Test
|
||||
public void securedUserWhenCustomAfterAdviceConfiguredAndNameBobThenGranted() {
|
||||
this.spring.configLocations(xml("CustomAuthorizationManagerAfterAdvice")).autowire();
|
||||
String result = this.methodSecurityService.securedUser();
|
||||
assertThat(result).isEqualTo("granted");
|
||||
}
|
||||
|
||||
@WithMockUser("joe")
|
||||
@Test
|
||||
public void securedUserWhenCustomAfterAdviceConfiguredAndNameNotBobThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("CustomAuthorizationManagerAfterAdvice")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::securedUser)
|
||||
.withMessage("Access Denied for User 'joe'");
|
||||
}
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void jsr250WhenRoleAdminThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabled")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.methodSecurityService::jsr250)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithAnonymousUser
|
||||
@Test
|
||||
public void jsr250PermitAllWhenRoleAnonymousThenPasses() {
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabled")).autowire();
|
||||
String result = this.methodSecurityService.jsr250PermitAll();
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void rolesAllowedUserWhenRoleAdminThenAccessDeniedException() {
|
||||
this.spring.configLocations(xml("BusinessService")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(this.businessService::rolesAllowedUser)
|
||||
.withMessage("Access Denied");
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void rolesAllowedUserWhenRoleUserThenPasses() {
|
||||
this.spring.configLocations(xml("BusinessService")).autowire();
|
||||
this.businessService.rolesAllowedUser();
|
||||
}
|
||||
|
||||
@WithMockUser(roles = { "ADMIN", "USER" })
|
||||
@Test
|
||||
public void manyAnnotationsWhenMeetsConditionsThenReturnsFilteredList() throws Exception {
|
||||
List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabled")).autowire();
|
||||
List<String> filtered = this.methodSecurityService.manyAnnotations(new ArrayList<>(names));
|
||||
assertThat(filtered).hasSize(2);
|
||||
assertThat(filtered).containsExactly("harold", "jonathan");
|
||||
}
|
||||
|
||||
// gh-4003
|
||||
// gh-4103
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void manyAnnotationsWhenUserThenFails() {
|
||||
List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabled")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
|
||||
}
|
||||
|
||||
@WithMockUser
|
||||
@Test
|
||||
public void manyAnnotationsWhenShortListThenFails() {
|
||||
List<String> names = Arrays.asList("harold", "jonathan", "pete");
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabled")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
|
||||
}
|
||||
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
@Test
|
||||
public void manyAnnotationsWhenAdminThenFails() {
|
||||
List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
|
||||
this.spring.configLocations(xml("MethodSecurityServiceEnabled")).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
|
||||
}
|
||||
|
||||
// gh-3183
|
||||
@Test
|
||||
public void repeatedAnnotationsWhenPresentThenFails() {
|
||||
this.spring.configLocations(xml("MethodSecurityService")).autowire();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> this.methodSecurityService.repeatedAnnotations());
|
||||
}
|
||||
|
||||
// gh-3183
|
||||
@Test
|
||||
public void repeatedJsr250AnnotationsWhenPresentThenFails() {
|
||||
this.spring.configLocations(xml("Jsr250")).autowire();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> this.businessService.repeatedAnnotations());
|
||||
}
|
||||
|
||||
// gh-3183
|
||||
@Test
|
||||
public void repeatedSecuredAnnotationsWhenPresentThenFails() {
|
||||
this.spring.configLocations(xml("Secured")).autowire();
|
||||
assertThatExceptionOfType(AnnotationConfigurationException.class)
|
||||
.isThrownBy(() -> this.businessService.repeatedAnnotations());
|
||||
}
|
||||
|
||||
private static String xml(String configName) {
|
||||
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
|
||||
}
|
||||
|
||||
static class MyPermissionEvaluator implements PermissionEvaluator {
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
|
||||
return "grant".equals(targetDomainObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
|
||||
Object permission) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MyAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
||||
|
||||
@Override
|
||||
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation object) {
|
||||
return new AuthorizationDecision("bob".equals(authentication.get().getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MyAdvice implements MethodInterceptor {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object invoke(@NotNull MethodInvocation invocation) {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if ("bob".equals(auth.getName())) {
|
||||
return "granted";
|
||||
}
|
||||
throw new AccessDeniedException("Access Denied for User '" + auth.getName() + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user