Skip to content

Commit

Permalink
Use delegate instead of ProxyFactoryBean
Browse files Browse the repository at this point in the history
  • Loading branch information
marcusdacoregio committed Dec 13, 2022
1 parent 5b8c5a3 commit c72a888
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -109,6 +107,9 @@ public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAu

public AuthenticationManager getAuthenticationManager() throws Exception {
if (this.authenticationManagerInitialized) {
if (this.authenticationManager instanceof LazyAuthenticationManager lazyAuthenticationManager) {
return lazyAuthenticationManager.getAuthenticationManager();
}
return this.authenticationManager;
}
AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
Expand Down Expand Up @@ -149,51 +150,8 @@ private AuthenticationEventPublisher getAuthenticationEventPublisher(Application
return this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
}

@SuppressWarnings("unchecked")
private <T> T lazyBean(Class<T> interfaceName) {
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.applicationContext,
interfaceName);
if (beanNamesForType.length == 0) {
return null;
}
String beanName = getBeanName(interfaceName, beanNamesForType);
lazyTargetSource.setTargetBeanName(beanName);
lazyTargetSource.setBeanFactory(this.applicationContext);
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
proxyFactory = this.objectPostProcessor.postProcess(proxyFactory);
proxyFactory.setTargetSource(lazyTargetSource);
return (T) proxyFactory.getObject();
}

private <T> String getBeanName(Class<T> interfaceName, String[] beanNamesForType) {
if (beanNamesForType.length == 1) {
return beanNamesForType[0];
}
List<String> primaryBeanNames = getPrimaryBeanNames(beanNamesForType);
Assert.isTrue(primaryBeanNames.size() != 0, () -> "Found " + beanNamesForType.length + " beans for type "
+ interfaceName + ", but none marked as primary");
Assert.isTrue(primaryBeanNames.size() == 1,
() -> "Found " + primaryBeanNames.size() + " beans for type " + interfaceName + " marked as primary");
return primaryBeanNames.get(0);
}

private List<String> getPrimaryBeanNames(String[] beanNamesForType) {
List<String> list = new ArrayList<>();
if (!(this.applicationContext instanceof ConfigurableApplicationContext)) {
return Collections.emptyList();
}
for (String beanName : beanNamesForType) {
if (((ConfigurableApplicationContext) this.applicationContext).getBeanFactory().getBeanDefinition(beanName)
.isPrimary()) {
list.add(beanName);
}
}
return list;
}

private AuthenticationManager getAuthenticationManagerBean() {
return lazyBean(AuthenticationManager.class);
return new LazyAuthenticationManager(this.applicationContext);
}

private static <T> T getBeanOrNull(ApplicationContext applicationContext, Class<T> type) {
Expand Down Expand Up @@ -344,4 +302,61 @@ public String toString() {

}

static class LazyAuthenticationManager implements AuthenticationManager {

private final ApplicationContext applicationContext;

private AuthenticationManager authenticationManager;

LazyAuthenticationManager(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return getAuthenticationManager().authenticate(authentication);
}

private AuthenticationManager getAuthenticationManager() {
if (this.authenticationManager != null) {
return this.authenticationManager;
}
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.applicationContext,
AuthenticationManager.class);
if (beanNamesForType.length == 0) {
return null;
}
String beanName = getBeanName(AuthenticationManager.class, beanNamesForType);
this.authenticationManager = (AuthenticationManager) this.applicationContext.getBean(beanName);
return this.authenticationManager;
}

private <T> String getBeanName(Class<T> interfaceName, String[] beanNamesForType) {
if (beanNamesForType.length == 1) {
return beanNamesForType[0];
}
List<String> primaryBeanNames = getPrimaryBeanNames(beanNamesForType);
Assert.isTrue(primaryBeanNames.size() != 0, () -> "Found " + beanNamesForType.length + " beans for type "
+ interfaceName + ", but none marked as primary");
Assert.isTrue(primaryBeanNames.size() == 1, () -> "Found " + primaryBeanNames.size() + " beans for type "
+ interfaceName + " marked as primary");
return primaryBeanNames.get(0);
}

private List<String> getPrimaryBeanNames(String[] beanNamesForType) {
List<String> list = new ArrayList<>();
if (!(this.applicationContext instanceof ConfigurableApplicationContext)) {
return Collections.emptyList();
}
for (String beanName : beanNamesForType) {
if (((ConfigurableApplicationContext) this.applicationContext).getBeanFactory()
.getBeanDefinition(beanName).isPrimary()) {
list.add(beanName);
}
}
return list;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -118,16 +117,22 @@ public void orderingAutowiredOnEnableWebMvcSecurity() {
@Test
public void getAuthenticationManagerWhenNoAuthenticationThenNull() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire();
assertThat(this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager())
.isNull();
AuthenticationManager authenticationManager = this.spring.getContext()
.getBean(AuthenticationConfiguration.class).getAuthenticationManager();
assertThat(authenticationManager).isInstanceOf(AuthenticationConfiguration.LazyAuthenticationManager.class);
assertThat(ReflectionTestUtils.<AuthenticationManager>invokeMethod(authenticationManager,
"getAuthenticationManager")).isNull();
}

@Test
public void getAuthenticationManagerWhenNoOpGlobalAuthenticationConfigurerAdapterThenNull() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class,
NoOpGlobalAuthenticationConfigurerAdapter.class).autowire();
assertThat(this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager())
.isNull();
AuthenticationManager authenticationManager = this.spring.getContext()
.getBean(AuthenticationConfiguration.class).getAuthenticationManager();
assertThat(authenticationManager).isInstanceOf(AuthenticationConfiguration.LazyAuthenticationManager.class);
assertThat(ReflectionTestUtils.<AuthenticationManager>invokeMethod(authenticationManager,
"getAuthenticationManager")).isNull();
}

@Test
Expand Down Expand Up @@ -184,17 +189,6 @@ public void getAuthenticationWhenNotConfiguredThenBootTrigger() throws Exception
authenticationManager.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("boot", "password"));
}

// gh-2531
@Test
public void getAuthenticationManagerWhenPostProcessThenUsesBeanClassLoaderOnProxyFactoryBean() throws Exception {
this.spring.register(Sec2531Config.class).autowire();
ObjectPostProcessor<Object> opp = this.spring.getContext().getBean(ObjectPostProcessor.class);
given(opp.postProcess(any())).willAnswer((a) -> a.getArgument(0));
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.getAuthenticationManager();
verify(opp).postProcess(any(ProxyFactoryBean.class));
}

@Test
public void getAuthenticationManagerWhenSec2822ThenCannotForceAuthenticationAlreadyBuilt() throws Exception {
this.spring.register(Sec2822WebSecurity.class, Sec2822UseAuth.class, Sec2822Config.class).autowire();
Expand Down

0 comments on commit c72a888

Please sign in to comment.