mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-04 20:39:22 +00:00
GlobalMethodSecurityConfigurationTests groovy->java
Issue: gh-4939
This commit is contained in:
parent
6c52eb6ee1
commit
6af1ac08db
@ -1,518 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl
|
||||
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
import org.springframework.beans.BeansException
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor
|
||||
import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter
|
||||
import org.springframework.security.config.annotation.method.configuration.NamespaceGlobalMethodSecurityTests.BaseMethodConfig
|
||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
||||
|
||||
import javax.sql.DataSource
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.ApplicationListener
|
||||
import org.springframework.context.annotation.AdviceMode
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
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.prepost.PreAuthorize
|
||||
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||
import org.springframework.security.config.method.TestPermissionEvaluator;
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.authority.AuthorityUtils
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
|
||||
def "messages set when using GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
|
||||
then:
|
||||
authenticationManager.messages.messageSource instanceof ApplicationContext
|
||||
}
|
||||
|
||||
def "AuthenticationEventPublisher is registered GlobalMethodSecurityConfiguration"() {
|
||||
when:
|
||||
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
|
||||
then:
|
||||
authenticationManager.eventPublisher instanceof DefaultAuthenticationEventPublisher
|
||||
when:
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken("user",null,AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||
authenticationManager.eventPublisher.publishAuthenticationSuccess(auth)
|
||||
then:
|
||||
InMemoryAuthWithGlobalMethodSecurityConfig.EVENT.authentication == auth
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration implements ApplicationListener<AuthenticationSuccessEvent> {
|
||||
static AuthenticationSuccessEvent EVENT
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AuthenticationSuccessEvent e) {
|
||||
EVENT = e
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticationManager getAuthenticationManager() {
|
||||
context.getBean(MethodInterceptor).authenticationManager
|
||||
}
|
||||
|
||||
def "AuthenticationTrustResolver autowires"() {
|
||||
setup:
|
||||
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
|
||||
when:
|
||||
loadConfig(CustomTrustResolverConfig)
|
||||
def preAdviceVoter = context.getBean(MethodInterceptor).accessDecisionManager.decisionVoters.find { it instanceof PreInvocationAuthorizationAdviceVoter}
|
||||
then:
|
||||
preAdviceVoter.preAdvice.expressionHandler.trustResolver == CustomTrustResolverConfig.TR
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class CustomTrustResolverConfig extends GlobalMethodSecurityConfiguration {
|
||||
static AuthenticationTrustResolver TR
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationTrustResolver tr() {
|
||||
return TR
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2301: DefaultWebSecurityExpressionHandler has BeanResolver set"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(ExpressionHandlerHasBeanResolverSetConfig)
|
||||
def service = context.getBean(ServiceImpl)
|
||||
when: "service with bean reference on PreAuthorize invoked"
|
||||
service.message()
|
||||
then: "properly throws AccessDeniedException"
|
||||
thrown(AccessDeniedException)
|
||||
when: "service with bean reference on PreAuthorize invoked"
|
||||
context.getBean(CustomAuthzService).grantAccess = true
|
||||
service.message()
|
||||
then: "grants access too"
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
|
||||
static class ExpressionHandlerHasBeanResolverSetConfig extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServiceImpl service() {
|
||||
return new ServiceImpl()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CustomAuthzService authz() {
|
||||
return new CustomAuthzService()
|
||||
}
|
||||
}
|
||||
|
||||
static class ServiceImpl {
|
||||
@PreAuthorize("@authz.authorize()")
|
||||
public String message() {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomAuthzService {
|
||||
boolean grantAccess
|
||||
|
||||
public boolean authorize() {
|
||||
grantAccess
|
||||
}
|
||||
}
|
||||
|
||||
def "Method Security supports annotations on interface parameter names"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(MethodSecurityServiceConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when: "service with annotated argument"
|
||||
service.postAnnotation('deny')
|
||||
then: "properly throws AccessDeniedException"
|
||||
thrown(AccessDeniedException)
|
||||
when: "service with annotated argument"
|
||||
service.postAnnotation('grant')
|
||||
then: "properly throws AccessDeniedException"
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class MethodSecurityServiceConfig extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "GlobalMethodSecurityConfiguration autowires PermissionEvaluator"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
PermissionEvaluator evaluator = Mock()
|
||||
AutowirePermissionEvaluatorConfig.PE = evaluator
|
||||
loadConfig(AutowirePermissionEvaluatorConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.hasPermission("something")
|
||||
then:
|
||||
1 * evaluator.hasPermission(_, "something", "read") >> true
|
||||
when:
|
||||
service.hasPermission("something")
|
||||
then:
|
||||
1 * evaluator.hasPermission(_, "something", "read") >> false
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class AutowirePermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
|
||||
static PermissionEvaluator PE
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PermissionEvaluator pe() {
|
||||
PE
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "GlobalMethodSecurityConfiguration does not failw with multiple PermissionEvaluator"() {
|
||||
when:
|
||||
loadConfig(MultiPermissionEvaluatorConfig)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public static class MultiPermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
|
||||
static PermissionEvaluator PE = new TestPermissionEvaluator()
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PermissionEvaluator pe() {
|
||||
PE
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PermissionEvaluator pe2() {
|
||||
PE
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2425: EnableGlobalMethodSecurity works on superclass"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(ParentConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
static class ChildConfig extends ParentConfig {}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class ParentConfig {
|
||||
|
||||
@Autowired
|
||||
protected void configurGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2479: Support AuthenticationManager in parent"() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
loadConfig(Sec2479ParentConfig)
|
||||
def child = new AnnotationConfigApplicationContext()
|
||||
child.register(Sec2479ChildConfig)
|
||||
child.parent = context
|
||||
child.refresh()
|
||||
MethodSecurityService service = child.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorize()
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
cleanup:
|
||||
child?.close()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Sec2479ParentConfig {
|
||||
static AuthenticationManager AM
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager am() {
|
||||
AM
|
||||
}
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class Sec2479ChildConfig {
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2815: @EnableGlobalMethodSecurity does not trigger eager initialization of Beans in GlobalAuthenticationConfigurer"() {
|
||||
setup:
|
||||
Sec2815Config.dataSource = Mock(DataSource)
|
||||
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
|
||||
loadConfig(Sec2815Config)
|
||||
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
|
||||
context.getBean(MockBeanPostProcessor).beforeInit['dataSource']
|
||||
context.getBean(MockBeanPostProcessor).afterInit['dataSource']
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class Sec2815Config {
|
||||
static DataSource dataSource;
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MockBeanPostProcessor mockBeanPostProcessor() {
|
||||
new MockBeanPostProcessor()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
dataSource
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AuthConfig extends GlobalAuthenticationConfigurerAdapter {
|
||||
@Autowired
|
||||
DataSource dataSource
|
||||
|
||||
@Override
|
||||
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
|
||||
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
beforeInit[beanName] = bean
|
||||
bean
|
||||
}
|
||||
|
||||
@Override
|
||||
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
afterInit[beanName] = bean
|
||||
bean
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-3045: Global Security proxies security"() {
|
||||
setup:
|
||||
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
|
||||
loadConfig(Sec3005Config)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
|
||||
!Proxy.isProxyClass(service.getClass())
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, mode= AdviceMode.ASPECTJ)
|
||||
@EnableTransactionManagement
|
||||
static class Sec3005Config {
|
||||
static DataSource dataSource;
|
||||
|
||||
@Bean
|
||||
public MethodSecurityService service() {
|
||||
new MethodSecurityServiceImpl()
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
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)
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@Configuration
|
||||
public static class PreAuthorizeBeanSpelConfig extends BaseMethodConfig {
|
||||
@Bean
|
||||
BeanSpelService service() {
|
||||
return new BeanSpelService();
|
||||
}
|
||||
@Bean
|
||||
BeanSpelSecurity security() {
|
||||
return new BeanSpelSecurity();
|
||||
}
|
||||
}
|
||||
|
||||
static class BeanSpelService {
|
||||
@PreAuthorize("@security.check(#arg)")
|
||||
void run(boolean arg) {}
|
||||
}
|
||||
|
||||
static class BeanSpelSecurity {
|
||||
public boolean check(boolean arg) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
// gh-3394
|
||||
def roleHierarchy() {
|
||||
setup:
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||
context = new AnnotationConfigApplicationContext(RoleHierarchyConfig)
|
||||
MethodSecurityService service = context.getBean(MethodSecurityService)
|
||||
when:
|
||||
service.preAuthorizeAdmin()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@Configuration
|
||||
public static class RoleHierarchyConfig extends BaseMethodConfig {
|
||||
@Bean
|
||||
RoleHierarchy roleHierarchy() {
|
||||
return new RoleHierarchyImpl(hierarchy:"ROLE_USER > ROLE_ADMIN")
|
||||
}
|
||||
}
|
||||
|
||||
def "GrantedAuthorityDefaults autowires"() {
|
||||
when:
|
||||
loadConfig(CustomGrantedAuthorityConfig)
|
||||
def preAdviceVoter = context.getBean(MethodInterceptor).accessDecisionManager.decisionVoters.find { it instanceof PreInvocationAuthorizationAdviceVoter}
|
||||
then:
|
||||
preAdviceVoter.preAdvice.expressionHandler.defaultRolePrefix == "ROLE:"
|
||||
}
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
static class CustomGrantedAuthorityConfig extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GrantedAuthorityDefaults ga() {
|
||||
return new GrantedAuthorityDefaults("ROLE:")
|
||||
}
|
||||
}
|
||||
}
|
@ -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() {}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user