From 7aabd8bf2d401504636bfe6ce00e57ea8ac7d473 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 31 Mar 2021 19:54:54 +0100 Subject: [PATCH] Ensure that class proxying is forced before AutoProxyCreator is created Previously, using @EnableGlobalMethodSecurity would cause the AutoProxyCreator to be created before the AOP auto-configuration had called AopUtils.forceAutoProxyCreatorToUseClassProxying. Forcing auto proxy creation changes the AutoProxyCreator's bean definition so it has no effect when attempted after the creator has been created. This commit updates the AOP auto-configuration to use a BeanFactoryPostProcessor to force the use of class proxying. This ensures that the changes to the auto proxy creator's bean definition are in place before any bean creation has been performed. Fixes gh-25413 --- .../aop/AopAutoConfiguration.java | 20 ++++++---- .../aop/AopAutoConfigurationTests.java | 40 ++++++++++++++++++- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/aop/AopAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/aop/AopAutoConfiguration.java index c9833dfa41..63f8d69ac8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/aop/AopAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/aop/AopAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-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. @@ -19,11 +19,12 @@ package org.springframework.boot.autoconfigure.aop; import org.aspectj.weaver.Advice; import org.springframework.aop.config.AopConfigUtils; -import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @@ -73,12 +74,15 @@ public class AopAutoConfiguration { matchIfMissing = true) static class ClassProxyingConfiguration { - ClassProxyingConfiguration(BeanFactory beanFactory) { - if (beanFactory instanceof BeanDefinitionRegistry) { - BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; - AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); - AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); - } + @Bean + static BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() { + return (beanFactory) -> { + if (beanFactory instanceof BeanDefinitionRegistry) { + BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; + AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); + AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); + } + }; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/aop/AopAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/aop/AopAutoConfigurationTests.java index 58a3e64d46..18b69aa51f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/aop/AopAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/aop/AopAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-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. @@ -18,9 +18,12 @@ package org.springframework.boot.autoconfigure.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; +import org.aspectj.weaver.Advice; import org.junit.jupiter.api.Test; +import org.springframework.aop.support.AopUtils; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; @@ -28,6 +31,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Import; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.web.bind.annotation.RequestMapping; import static org.assertj.core.api.Assertions.assertThat; @@ -74,6 +80,17 @@ class AopAutoConfigurationTests { @Test void customConfigurationWithProxyTargetClassDefaultDoesNotDisableProxying() { this.contextRunner.withUserConfiguration(CustomTestConfiguration.class).run(proxyTargetClassEnabled()); + + } + + @Test + void whenGlobalMethodSecurityIsEnabledAndAspectJIsNotAvailableThenClassProxyingIsStillUsedByDefault() { + this.contextRunner.withClassLoader(new FilteredClassLoader(Advice.class)) + .withUserConfiguration(ExampleController.class, EnableGlobalMethodSecurityConfiguration.class) + .run((context) -> { + ExampleController exampleController = context.getBean(ExampleController.class); + assertThat(AopUtils.isCglibProxy(exampleController)).isTrue(); + }); } private ContextConsumer proxyTargetClassEnabled() { @@ -149,4 +166,25 @@ class AopAutoConfigurationTests { } + @EnableGlobalMethodSecurity(prePostEnabled = true) + @Configuration(proxyBeanMethods = false) + static class EnableGlobalMethodSecurityConfiguration { + + } + + public static class ExampleController implements TestInterface { + + @RequestMapping("/test") + @PreAuthorize("true") + String demo() { + return "test"; + } + + @Override + public void foo() { + + } + + } + }