Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ProxyFactoryBean on AuthenticationManager does not work in native mode #12367

Closed
marcusdacoregio opened this issue Dec 12, 2022 · 1 comment
Closed
Assignees
Labels
in: core An issue in spring-security-core type: bug A general bug
Milestone

Comments

@marcusdacoregio
Copy link
Contributor

If we don’t find an AuthenticationManager bean during configuration, we create a ProxyFactoryBean to lazily initialize the bean when used.

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();
}

This does not work when running an application in native mode, since some proxy hints are necessary in order to find the bean.
Instead, we should delay the initialization of the bean and provide a delegate instead of a lazy bean, something like AuthenticationConfiguration#LazyPasswordEncoder.

Stacktrace:

2022-11-28T23:48:23.496+01:00 ERROR 29336 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration': Unsatisfied dependency expressed through field 'httpSecurity': Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity': Instantiation of supplied bean failed
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveValue(AutowiredFieldValueResolver.java:195) ~[na:na]
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveAndSet(AutowiredFieldValueResolver.java:167) ~[na:na]
        at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration__Autowiring.apply(WebSecurityConfiguration__Autowiring.java:20) ~[na:na]
        at org.springframework.beans.factory.support.InstanceSupplier$1.get(InstanceSupplier.java:82) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[demo.exe:6.0.2]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[demo.exe:6.0.2]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[demo.exe:6.0.2]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[demo.exe:3.0.0]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[demo.exe:3.0.0]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[demo.exe:3.0.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[demo.exe:3.0.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[demo.exe:3.0.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[demo.exe:3.0.0]
        at com.example.demo.DemoApplication.main(DemoApplication.java:10) ~[demo.exe:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity': Instantiation of supplied bean failed
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1236) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:344) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveValue(AutowiredFieldValueResolver.java:189) ~[na:na]
        ... 22 common frames omitted
Caused by: com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface org.springframework.security.authentication.AuthenticationManager, interface org.springframework.aop.SpringProxy, interface org.springframework.aop.framework.Advised, interface org.springframework.core.DecoratingProxy] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:89) ~[na:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.reflect.proxy.DynamicProxySupport.getProxyClass(DynamicProxySupport.java:171) ~[na:na]
        at [email protected]/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:47) ~[demo.exe:na]
        at [email protected]/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1037) ~[demo.exe:na]
        at org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:123) ~[na:na]
        at org.springframework.aop.framework.ProxyFactoryBean.getProxy(ProxyFactoryBean.java:348) ~[na:na]
        at org.springframework.aop.framework.ProxyFactoryBean.getSingletonInstance(ProxyFactoryBean.java:306) ~[na:na]
        at org.springframework.aop.framework.ProxyFactoryBean.getObject(ProxyFactoryBean.java:253) ~[na:na]
        at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.lazyBean(AuthenticationConfiguration.java:166) ~[demo.exe:na]
        at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationManagerBean(AuthenticationConfiguration.java:196) ~[demo.exe:na]
        at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationManager(AuthenticationConfiguration.java:123) ~[demo.exe:na]
        at org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.authenticationManager(HttpSecurityConfiguration.java:132) ~[demo.exe:na]
        at org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity(HttpSecurityConfiguration.java:108) ~[demo.exe:na]
        at org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration__BeanDefinitions.lambda$getHttpSecurityInstanceSupplier$0(HttpSecurityConfiguration__BeanDefinitions.java:31) ~[na:na]
        at org.springframework.util.function.ThrowingFunction.apply(ThrowingFunction.java:63) ~[demo.exe:6.0.2]
        at org.springframework.util.function.ThrowingFunction.apply(ThrowingFunction.java:51) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$withGenerator$0(BeanInstanceSupplier.java:173) ~[na:na]
        at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[demo.exe:6.0.2]
        at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:208) ~[na:na]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59) ~[demo.exe:6.0.2]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47) ~[demo.exe:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:220) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:208) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[demo.exe:6.0.2]
        ... 32 common frames omitted

This was initially reported by @nkonev in #12366.

@marcusdacoregio marcusdacoregio added in: core An issue in spring-security-core type: bug A general bug labels Dec 12, 2022
@marcusdacoregio marcusdacoregio added this to the 6.0.1 milestone Dec 12, 2022
@marcusdacoregio marcusdacoregio self-assigned this Dec 12, 2022
marcusdacoregio added a commit to marcusdacoregio/spring-security that referenced this issue Dec 13, 2022
@marcusdacoregio
Copy link
Contributor Author

For historical reasons, instead of providing a delegate, we should create a BeanRegistrationAotProcessor and provide the necessary hints if a bean of AuthenticationManager is present.

The delegate seems to be more eager than the ProxyFactoryBean. The ProxyFactoryBean does not look up the bean until a method on the bean needs to be invoked. Using a delegate looks like it will do the lookup as soon as a bean requires the AuthenticationManager. This tended to cause problems around AOP which gets instantiated very early on and can require the AuthenticationManager in some cases

@marcusdacoregio marcusdacoregio changed the title Lazy AuthenticationManager does not work in native image ProxyFactoryBean on AuthenticationManager does not work in native image Dec 14, 2022
@marcusdacoregio marcusdacoregio changed the title ProxyFactoryBean on AuthenticationManager does not work in native image ProxyFactoryBean on AuthenticationManager does not work in native mode Dec 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core An issue in spring-security-core type: bug A general bug
Projects
None yet
Development

No branches or pull requests

1 participant