GlobalMethodSecurityConfigurationTests groovy->java

Issue: gh-4939
This commit is contained in:
Rob Winch
2018-02-12 16:28:12 -06:00
parent 6c52eb6ee1
commit 6af1ac08db
2 changed files with 484 additions and 518 deletions

View File

@@ -0,0 +1,484 @@
/*
* Copyright 2002-2018 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
*
* http://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 org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.config.MockEventListener;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import javax.sql.DataSource;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
*
* @author Rob Winch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SecurityTestExecutionListeners
public class GlobalMethodSecurityConfigurationTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@Autowired(required = false)
private MethodSecurityService service;
private AuthenticationManager authenticationManager;
@Autowired
public void setMethodInterceptor(MethodSecurityInterceptor interceptor) {
this.authenticationManager = interceptor.getAuthenticationManager();
}
@Autowired(required = false)
MockEventListener<AbstractAuthenticationEvent> events;
@Test
public void methodSecurityAuthenticationManagerPublishesEvent() {
this.spring.register(InMemoryAuthWithGlobalMethodSecurityConfig.class).autowire();
try {
this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("foo", "bar"));
} catch(AuthenticationException e) {}
assertThat(this.events.getEvents()).extracting(Object::getClass).containsOnly((Class) AuthenticationFailureBadCredentialsEvent.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication();
}
@Bean
public MockEventListener<AbstractAuthenticationEvent> listener() {
return new MockEventListener<AbstractAuthenticationEvent>() {};
}
}
@Test
@WithMockUser
public void methodSecurityWhenAuthenticationTrustResolverIsBeanThenAutowires() {
this.spring.register(CustomTrustResolverConfig.class).autowire();
AuthenticationTrustResolver trustResolver = this.spring.getContext().getBean(AuthenticationTrustResolver.class);
when(trustResolver.isAnonymous(any())).thenReturn(true, false);
assertThatThrownBy(() -> this.service.preAuthorizeNotAnonymous())
.isInstanceOf(AccessDeniedException.class);
this.service.preAuthorizeNotAnonymous();
verify(trustResolver, atLeastOnce()).isAnonymous(any());
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomTrustResolverConfig {
@Bean
public AuthenticationTrustResolver trustResolver() {
return mock(AuthenticationTrustResolver.class);
}
@Bean
public MethodSecurityServiceImpl service() {
return new MethodSecurityServiceImpl();
}
}
// SEC-2301
@Test
@WithMockUser
public void defaultWebSecurityExpressionHandlerHasBeanResolverSet() {
this.spring.register(ExpressionHandlerHasBeanResolverSetConfig.class).autowire();
Authz authz = this.spring.getContext().getBean(Authz.class);
assertThatThrownBy(() -> this.service.preAuthorizeBean(false))
.isInstanceOf(AccessDeniedException.class);
this.service.preAuthorizeBean(true);
}
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
static class ExpressionHandlerHasBeanResolverSetConfig {
@Bean
public MethodSecurityServiceImpl service() {
return new MethodSecurityServiceImpl();
}
@Bean
public Authz authz() {
return new Authz();
}
}
@Test
@WithMockUser
public void methodSecuritySupportsAnnotaitonsOnInterfaceParamerNames() {
this.spring.register(MethodSecurityServiceConfig.class).autowire();
assertThatThrownBy(() -> this.service.postAnnotation("deny"))
.isInstanceOf(AccessDeniedException.class);
this.service.postAnnotation("grant");
// no exception
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityServiceConfig {
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@Test
@WithMockUser
public void globalMethodSecurityConfigurationAutowiresPermissionEvaluator() {
this.spring.register(AutowirePermissionEvaluatorConfig.class).autowire();
PermissionEvaluator permission = this.spring.getContext().getBean(PermissionEvaluator.class);
when(permission.hasPermission(any(), eq("something"), eq("read"))).thenReturn(true, false);
this.service.hasPermission("something");
// no exception
assertThatThrownBy(() -> this.service.hasPermission("something"))
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class AutowirePermissionEvaluatorConfig {
@Bean
public PermissionEvaluator permissionEvaluator() {
return mock(PermissionEvaluator.class);
}
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@Test
public void multiPermissionEvaluatorConfig() throws Exception {
this.spring.register(MultiPermissionEvaluatorConfig.class).autowire();
// no exception
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class MultiPermissionEvaluatorConfig {
@Bean
public PermissionEvaluator permissionEvaluator() {
return mock(PermissionEvaluator.class);
}
@Bean
public PermissionEvaluator permissionEvaluator2() {
return mock(PermissionEvaluator.class);
}
}
// SEC-2425
@Test
@WithMockUser
public void enableGlobalMethodSecurityWorksOnSuperclass() {
this.spring.register(ChildConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
}
@Configuration
static class ChildConfig extends ParentConfig {}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class ParentConfig {
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
// SEC-2479
@Test
@WithMockUser
public void supportAuthenticationManagerInParent() {
try (AnnotationConfigWebApplicationContext parent = new AnnotationConfigWebApplicationContext()) {
parent.register(Sec2479ParentConfig.class);
parent.refresh();
try (AnnotationConfigWebApplicationContext child = new AnnotationConfigWebApplicationContext()) {
child.setParent(parent);
child.register(Sec2479ChildConfig.class);
child.refresh();
this.spring.context(child).autowire();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
}
}
}
@Configuration
static class Sec2479ParentConfig {
@Bean
public AuthenticationManager am() {
return mock(AuthenticationManager.class);
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2479ChildConfig {
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@Test
public void enableGlobalMethodSecurityDoesNotTriggerEagerInitializationOfBeansInGlobalAuthenticationConfigurer() {
this.spring.register(Sec2815Config.class).autowire();
MockBeanPostProcessor pp = this.spring.getContext().getBean(MockBeanPostProcessor.class);
assertThat(pp.beforeInit).containsKeys("dataSource");
assertThat(pp.afterInit).containsKeys("dataSource");
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2815Config {
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
@Bean
public MockBeanPostProcessor mockBeanPostProcessor() {
return new MockBeanPostProcessor();
}
@Bean
public DataSource dataSource() {
return mock(DataSource.class);
}
@Configuration
static class AuthConfig extends GlobalAuthenticationConfigurerAdapter {
@Autowired
DataSource dataSource;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
}
}
static class MockBeanPostProcessor implements BeanPostProcessor {
Map<String,Object> beforeInit = new HashMap<String,Object>();
Map<String,Object> afterInit = new HashMap<String,Object>();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws
BeansException {
this.beforeInit.put(beanName, bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
this.afterInit.put(beanName, bean);
return bean;
}
}
// SEC-3045
@Test
public void globalSecurityProxiesSecurity() {
this.spring.register(Sec3005Config.class).autowire();
assertThat(this.service.getClass()).matches(c-> !Proxy.isProxyClass(c), "is not proxy class");
}
@EnableGlobalMethodSecurity(prePostEnabled = true, mode= AdviceMode.ASPECTJ)
@EnableTransactionManagement
static class Sec3005Config {
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
}
//
// // gh-3797
// def preAuthorizeBeanSpel() {
// setup:
// SecurityContextHolder.getContext().setAuthentication(
// new TestingAuthenticationToken("user", "password","ROLE_USER"))
// context = new AnnotationConfigApplicationContext(PreAuthorizeBeanSpelConfig)
// BeanSpelService service = context.getBean(BeanSpelService)
// when:
// service.run(true)
// then:
// noExceptionThrown()
// when:
// service.run(false)
// then:
// thrown(AccessDeniedException)
// }
//
@Test
@WithMockUser
public void preAuthorizeBeanSpel() {
this.spring.register(PreAuthorizeBeanSpelConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorizeBean(false))
.isInstanceOf(AccessDeniedException.class);
this.service.preAuthorizeBean(true);
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class PreAuthorizeBeanSpelConfig {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
@Bean
Authz authz() {
return new Authz();
}
}
// gh-3394
@Test
@WithMockUser
public void roleHierarchy() {
this.spring.register(RoleHierarchyConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
this.service.preAuthorizeAdmin();
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class RoleHierarchyConfig {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl result = new RoleHierarchyImpl();
result.setHierarchy("ROLE_USER > ROLE_ADMIN");
return result;
}
}
@Test
@WithMockUser(authorities = "ROLE:USER")
public void grantedAuthorityDefaultsAutowires() {
this.spring.register(CustomGrantedAuthorityConfig.class).autowire();
CustomGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext().getBean(
CustomGrantedAuthorityConfig.CustomAuthorityService.class);
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
customService.customPrefixRoleUser();
// no exception
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomGrantedAuthorityConfig {
@Bean
public GrantedAuthorityDefaults ga() {
return new GrantedAuthorityDefaults("ROLE:");
}
@Bean
public CustomAuthorityService service() {
return new CustomAuthorityService();
}
@Bean
public MethodSecurityServiceImpl methodSecurityService() {
return new MethodSecurityServiceImpl();
}
static class CustomAuthorityService {
@PreAuthorize("hasRole('ROLE:USER')")
public void customPrefixRoleUser() {}
}
}
}