SEC-2595: @EnableGlobalMethodSecurity AspectJ fixes
This commit is contained in:
		
							parent
							
								
									44f688c9d2
								
							
						
					
					
						commit
						b2d66e2a78
					
				| 
						 | 
				
			
			@ -59,7 +59,7 @@ ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && pr
 | 
			
		|||
ext.sampleProjects = subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
 | 
			
		||||
ext.itestProjects = subprojects.findAll { project -> project.name.startsWith('itest') }
 | 
			
		||||
ext.coreModuleProjects = javaProjects - sampleProjects - itestProjects
 | 
			
		||||
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj-xml')]
 | 
			
		||||
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj-xml'), project(':spring-security-samples-aspectj-jc')]
 | 
			
		||||
 | 
			
		||||
configure(allprojects - javaProjects) {
 | 
			
		||||
    task afterEclipseImport {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,8 @@ package org.springframework.security.config.annotation.method.configuration;
 | 
			
		|||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.springframework.aop.config.AopConfigUtils;
 | 
			
		||||
import org.springframework.beans.factory.config.BeanDefinition;
 | 
			
		||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 | 
			
		||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 | 
			
		||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationAttributes;
 | 
			
		||||
| 
						 | 
				
			
			@ -50,18 +52,15 @@ class GlobalMethodSecurityAspectJAutoProxyRegistrar implements
 | 
			
		|||
            AnnotationMetadata importingClassMetadata,
 | 
			
		||||
            BeanDefinitionRegistry registry) {
 | 
			
		||||
 | 
			
		||||
        AopConfigUtils
 | 
			
		||||
                .registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
 | 
			
		||||
        BeanDefinition interceptor = registry.getBeanDefinition("methodSecurityInterceptor");
 | 
			
		||||
 | 
			
		||||
        Map<String, Object> annotationAttributes = importingClassMetadata
 | 
			
		||||
                .getAnnotationAttributes(EnableGlobalMethodSecurity.class
 | 
			
		||||
                        .getName());
 | 
			
		||||
        AnnotationAttributes enableAJAutoProxy = AnnotationAttributes
 | 
			
		||||
                .fromMap(annotationAttributes);
 | 
			
		||||
        BeanDefinitionBuilder aspect =
 | 
			
		||||
                BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
 | 
			
		||||
        aspect.setFactoryMethod("aspectOf");
 | 
			
		||||
        aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
 | 
			
		||||
        aspect.addPropertyValue("securityInterceptor", interceptor);
 | 
			
		||||
 | 
			
		||||
        if (enableAJAutoProxy.getBoolean("proxyTargetClass")) {
 | 
			
		||||
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
 | 
			
		||||
        }
 | 
			
		||||
        registry.registerBeanDefinition("annotationSecurityAspect$0", aspect.getBeanDefinition());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,10 +24,7 @@ import org.apache.commons.logging.Log;
 | 
			
		|||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
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.Configuration;
 | 
			
		||||
import org.springframework.context.annotation.ImportAware;
 | 
			
		||||
import org.springframework.context.annotation.Role;
 | 
			
		||||
import org.springframework.context.annotation.*;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationAttributes;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationUtils;
 | 
			
		||||
import org.springframework.core.type.AnnotationMetadata;
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +45,7 @@ import org.springframework.security.access.intercept.AfterInvocationProviderMana
 | 
			
		|||
import org.springframework.security.access.intercept.RunAsManager;
 | 
			
		||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
 | 
			
		||||
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
 | 
			
		||||
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
 | 
			
		||||
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
 | 
			
		||||
import org.springframework.security.access.method.MethodSecurityMetadataSource;
 | 
			
		||||
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +109,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
 | 
			
		|||
     */
 | 
			
		||||
    @Bean
 | 
			
		||||
    public MethodInterceptor methodSecurityInterceptor() throws Exception {
 | 
			
		||||
        MethodSecurityInterceptor methodSecurityInterceptor = new MethodSecurityInterceptor();
 | 
			
		||||
        MethodSecurityInterceptor methodSecurityInterceptor = isAspectJ() ? new AspectJMethodSecurityInterceptor() : new MethodSecurityInterceptor();
 | 
			
		||||
        methodSecurityInterceptor
 | 
			
		||||
                .setAccessDecisionManager(accessDecisionManager());
 | 
			
		||||
        methodSecurityInterceptor
 | 
			
		||||
| 
						 | 
				
			
			@ -379,6 +377,10 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
 | 
			
		|||
        return (Integer) enableMethodSecurity().get("order");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean isAspectJ() {
 | 
			
		||||
        return enableMethodSecurity().getEnum("mode") == AdviceMode.ASPECTJ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private AnnotationAttributes enableMethodSecurity() {
 | 
			
		||||
        if (enableMethodSecurity == null) {
 | 
			
		||||
            // if it is null look at this instance (i.e. a subclass was used)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
 | 
			
		||||
dependencies {
 | 
			
		||||
    compile project(':spring-security-core'),
 | 
			
		||||
            project(':spring-security-config')
 | 
			
		||||
 | 
			
		||||
    aspectpath project(':spring-security-aspects')
 | 
			
		||||
 | 
			
		||||
    runtime project(':spring-security-aspects')
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 sample.aspectj;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.annotation.AdviceMode;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 | 
			
		||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Rob Winch
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ,securedEnabled = true)
 | 
			
		||||
public class AspectjSecurityConfig {
 | 
			
		||||
	@Bean
 | 
			
		||||
	public Service service() {
 | 
			
		||||
		return new Service();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Bean
 | 
			
		||||
	public SecuredService securedService() {
 | 
			
		||||
		return new SecuredService();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
 | 
			
		||||
		auth.inMemoryAuthentication();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
package sample.aspectj;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.access.annotation.Secured;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service which is secured on the class level
 | 
			
		||||
 *
 | 
			
		||||
 * @author Mike Wiesner
 | 
			
		||||
 * @since 3.0
 | 
			
		||||
 */
 | 
			
		||||
@Secured("ROLE_USER")
 | 
			
		||||
public class SecuredService {
 | 
			
		||||
 | 
			
		||||
    public void secureMethod() {
 | 
			
		||||
        // nothing
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
package sample.aspectj;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.access.annotation.Secured;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service which is secured on method level
 | 
			
		||||
 *
 | 
			
		||||
 * @author Mike Wiesner
 | 
			
		||||
 * @since 1.0
 | 
			
		||||
 */
 | 
			
		||||
public class Service {
 | 
			
		||||
 | 
			
		||||
    @Secured("ROLE_USER")
 | 
			
		||||
    public void secureMethod() {
 | 
			
		||||
        // nothing
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void publicMethod() {
 | 
			
		||||
        // nothing
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,93 @@
 | 
			
		|||
package sample.aspectj;
 | 
			
		||||
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
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.authentication.AuthenticationCredentialsNotFoundException;
 | 
			
		||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 | 
			
		||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 | 
			
		||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.authority.AuthorityUtils;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.test.context.ContextConfiguration;
 | 
			
		||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Proxy;
 | 
			
		||||
 | 
			
		||||
import static org.fest.assertions.Assertions.assertThat;
 | 
			
		||||
 | 
			
		||||
@RunWith(SpringJUnit4ClassRunner.class)
 | 
			
		||||
@ContextConfiguration(classes=AspectjSecurityConfig.class)
 | 
			
		||||
public class AspectJInterceptorTests {
 | 
			
		||||
    private Authentication admin = new UsernamePasswordAuthenticationToken("test", "xxx", AuthorityUtils.createAuthorityList("ROLE_ADMIN"));
 | 
			
		||||
    private Authentication user = new UsernamePasswordAuthenticationToken("test", "xxx", AuthorityUtils.createAuthorityList("ROLE_USER"));
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private Service service;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private SecuredService securedService;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void publicMethod() throws Exception {
 | 
			
		||||
        service.publicMethod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = AuthenticationCredentialsNotFoundException.class)
 | 
			
		||||
    public void securedMethodNotAuthenticated() throws Exception {
 | 
			
		||||
        service.secureMethod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = AccessDeniedException.class)
 | 
			
		||||
    public void securedMethodWrongRole() throws Exception {
 | 
			
		||||
        SecurityContextHolder.getContext().setAuthentication(admin);
 | 
			
		||||
        service.secureMethod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void securedMethodEverythingOk() throws Exception {
 | 
			
		||||
        SecurityContextHolder.getContext().setAuthentication(user);
 | 
			
		||||
        service.secureMethod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = AuthenticationCredentialsNotFoundException.class)
 | 
			
		||||
    public void securedClassNotAuthenticated() throws Exception {
 | 
			
		||||
        securedService.secureMethod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = AccessDeniedException.class)
 | 
			
		||||
    public void securedClassWrongRole() throws Exception {
 | 
			
		||||
        SecurityContextHolder.getContext().setAuthentication(admin);
 | 
			
		||||
        securedService.secureMethod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = AccessDeniedException.class)
 | 
			
		||||
    public void securedClassWrongRoleOnNewedInstance() throws Exception {
 | 
			
		||||
        SecurityContextHolder.getContext().setAuthentication(admin);
 | 
			
		||||
        new SecuredService().secureMethod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void securedClassEverythingOk() throws Exception {
 | 
			
		||||
        SecurityContextHolder.getContext().setAuthentication(user);
 | 
			
		||||
        securedService.secureMethod();
 | 
			
		||||
        new SecuredService().secureMethod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // SEC-2595
 | 
			
		||||
    @Test
 | 
			
		||||
    public void notProxy() {
 | 
			
		||||
        assertThat(Proxy.isProxyClass(securedService.getClass())).isFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @After
 | 
			
		||||
    public void tearDown() {
 | 
			
		||||
        SecurityContextHolder.clearContext();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
<configuration>
 | 
			
		||||
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 | 
			
		||||
    <encoder>
 | 
			
		||||
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
 | 
			
		||||
    </encoder>
 | 
			
		||||
  </appender>
 | 
			
		||||
 | 
			
		||||
  <logger name="org.springframework.security" level="${sec.log.level}:-WARN"/>
 | 
			
		||||
 | 
			
		||||
  <root level="${root.level}:-WARN">
 | 
			
		||||
    <appender-ref ref="STDOUT" />
 | 
			
		||||
  </root>
 | 
			
		||||
 | 
			
		||||
</configuration>
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ def String[] samples = [
 | 
			
		|||
    'contacts-xml',
 | 
			
		||||
    'openid-xml',
 | 
			
		||||
    'aspectj-xml',
 | 
			
		||||
    'aspectj-jc',
 | 
			
		||||
    'gae-xml',
 | 
			
		||||
    'dms-xml',
 | 
			
		||||
    'preauth-xml',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue