mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-30 22:28:46 +00:00 
			
		
		
		
	Merge branch '6.1.x' into 6.2.x
Closes gh-14865
This commit is contained in:
		
						commit
						697d0c9af4
					
				| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright 2002-2018 the original author or authors. | ||||
|  * Copyright 2002-2024 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. | ||||
| @ -22,11 +22,14 @@ import java.util.List; | ||||
| import org.apache.commons.logging.Log; | ||||
| import org.apache.commons.logging.LogFactory; | ||||
| 
 | ||||
| import org.springframework.aop.support.AopUtils; | ||||
| import org.springframework.beans.factory.Aware; | ||||
| import org.springframework.beans.factory.DisposableBean; | ||||
| import org.springframework.beans.factory.InitializingBean; | ||||
| import org.springframework.beans.factory.ObjectProvider; | ||||
| import org.springframework.beans.factory.SmartInitializingSingleton; | ||||
| import org.springframework.beans.factory.config.AutowireCapableBeanFactory; | ||||
| import org.springframework.core.NativeDetector; | ||||
| import org.springframework.security.config.annotation.ObjectPostProcessor; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| @ -55,14 +58,13 @@ final class AutowireBeanFactoryObjectPostProcessor | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	public <T> T postProcess(T object) { | ||||
| 		if (object == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		T result = null; | ||||
| 		try { | ||||
| 			result = (T) this.autowireBeanFactory.initializeBean(object, object.toString()); | ||||
| 			result = initializeBeanIfNeeded(object); | ||||
| 		} | ||||
| 		catch (RuntimeException ex) { | ||||
| 			Class<?> type = object.getClass(); | ||||
| @ -78,6 +80,36 @@ final class AutowireBeanFactoryObjectPostProcessor | ||||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Invokes {@link AutowireCapableBeanFactory#initializeBean(Object, String)} only if | ||||
| 	 * needed, i.e when the application is not a native image or the object is not a CGLIB | ||||
| 	 * proxy. | ||||
| 	 * @param object the object to initialize | ||||
| 	 * @param <T> the type of the object | ||||
| 	 * @return the initialized bean or an existing bean if the object is a CGLIB proxy and | ||||
| 	 * the application is a native image | ||||
| 	 * @see <a href= | ||||
| 	 * "https://github.com/spring-projects/spring-security/issues/14825">Issue | ||||
| 	 * gh-14825</a> | ||||
| 	 */ | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	private <T> T initializeBeanIfNeeded(T object) { | ||||
| 		if (!NativeDetector.inNativeImage() || !AopUtils.isCglibProxy(object)) { | ||||
| 			return (T) this.autowireBeanFactory.initializeBean(object, object.toString()); | ||||
| 		} | ||||
| 		ObjectProvider<?> provider = this.autowireBeanFactory.getBeanProvider(object.getClass()); | ||||
| 		Object bean = provider.getIfUnique(); | ||||
| 		if (bean == null) { | ||||
| 			String msg = """ | ||||
| 					Failed to resolve an unique bean (single or primary) of type [%s] from the BeanFactory. | ||||
| 					Because the object is a CGLIB Proxy, a raw bean cannot be initialized during runtime in a native image. | ||||
| 					""" | ||||
| 				.formatted(object.getClass()); | ||||
| 			throw new IllegalStateException(msg); | ||||
| 		} | ||||
| 		return (T) bean; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void afterSingletonsInstantiated() { | ||||
| 		for (SmartInitializingSingleton singleton : this.smartSingletons) { | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright 2002-2018 the original author or authors. | ||||
|  * Copyright 2002-2024 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. | ||||
| @ -16,9 +16,13 @@ | ||||
| 
 | ||||
| package org.springframework.security.config.annotation.configuration; | ||||
| 
 | ||||
| import java.lang.reflect.Modifier; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.junit.jupiter.api.extension.ExtendWith; | ||||
| import org.mockito.Mockito; | ||||
| 
 | ||||
| import org.springframework.aop.framework.ProxyFactory; | ||||
| import org.springframework.beans.factory.BeanClassLoaderAware; | ||||
| import org.springframework.beans.factory.BeanFactoryAware; | ||||
| import org.springframework.beans.factory.DisposableBean; | ||||
| @ -31,13 +35,16 @@ import org.springframework.context.EnvironmentAware; | ||||
| import org.springframework.context.MessageSourceAware; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.core.NativeDetector; | ||||
| import org.springframework.security.config.annotation.ObjectPostProcessor; | ||||
| import org.springframework.security.config.test.SpringTestContext; | ||||
| import org.springframework.security.config.test.SpringTestContextExtension; | ||||
| import org.springframework.web.context.ServletContextAware; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| import static org.assertj.core.api.Assertions.assertThatException; | ||||
| import static org.mockito.ArgumentMatchers.isNotNull; | ||||
| import static org.mockito.BDDMockito.given; | ||||
| import static org.mockito.Mockito.mock; | ||||
| import static org.mockito.Mockito.verify; | ||||
| 
 | ||||
| @ -132,6 +139,59 @@ public class AutowireBeanFactoryObjectPostProcessorTests { | ||||
| 		assertThat(bean.doStuff()).isEqualTo("null"); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void postProcessWhenObjectIsCgLibProxyAndInNativeImageThenUseExistingBean() { | ||||
| 		try (var detector = Mockito.mockStatic(NativeDetector.class)) { | ||||
| 			given(NativeDetector.inNativeImage()).willReturn(true); | ||||
| 
 | ||||
| 			ProxyFactory proxyFactory = new ProxyFactory(new MyClass()); | ||||
| 			proxyFactory.setProxyTargetClass(!Modifier.isFinal(MyClass.class.getModifiers())); | ||||
| 			MyClass myClass = (MyClass) proxyFactory.getProxy(); | ||||
| 
 | ||||
| 			this.spring.register(Config.class, myClass.getClass()).autowire(); | ||||
| 			this.spring.getContext().getBean(myClass.getClass()).setIdentifier("0000"); | ||||
| 
 | ||||
| 			MyClass postProcessed = this.objectObjectPostProcessor.postProcess(myClass); | ||||
| 			assertThat(postProcessed.getIdentifier()).isEqualTo("0000"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void postProcessWhenObjectIsCgLibProxyAndInNativeImageAndBeanDoesNotExistsThenIllegalStateException() { | ||||
| 		try (var detector = Mockito.mockStatic(NativeDetector.class)) { | ||||
| 			given(NativeDetector.inNativeImage()).willReturn(true); | ||||
| 
 | ||||
| 			ProxyFactory proxyFactory = new ProxyFactory(new MyClass()); | ||||
| 			proxyFactory.setProxyTargetClass(!Modifier.isFinal(MyClass.class.getModifiers())); | ||||
| 			MyClass myClass = (MyClass) proxyFactory.getProxy(); | ||||
| 
 | ||||
| 			this.spring.register(Config.class).autowire(); | ||||
| 
 | ||||
| 			assertThatException().isThrownBy(() -> this.objectObjectPostProcessor.postProcess(myClass)) | ||||
| 				.havingRootCause() | ||||
| 				.isInstanceOf(IllegalStateException.class) | ||||
| 				.withMessage( | ||||
| 						""" | ||||
| 								Failed to resolve an unique bean (single or primary) of type [class org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessorTests$MyClass$$SpringCGLIB$$0] from the BeanFactory. | ||||
| 								Because the object is a CGLIB Proxy, a raw bean cannot be initialized during runtime in a native image. | ||||
| 								"""); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	static class MyClass { | ||||
| 
 | ||||
| 		private String identifier = "1234"; | ||||
| 
 | ||||
| 		String getIdentifier() { | ||||
| 			return this.identifier; | ||||
| 		} | ||||
| 
 | ||||
| 		void setIdentifier(String identifier) { | ||||
| 			this.identifier = identifier; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@Configuration | ||||
| 	static class Config { | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user