I am adding support for the @PreAuthorize
, @PreFilter
, @PostAuthorize
, and @PostFilter
annotations from Spring Security.
The hints are being added using a PrePostSecuredBeanRegistrationAotProcessor
and PrePostSecuredBeanRegistrationAotContribution
, which can be seen here, that's pretty much what we had before in the native repository.
However, the application fails when running on native with the following stacktrace:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'greetingServiceImpl' is expected to be of type 'com.example.methodsecurity.GreetingService' but was actually of type 'jdk.proxy4.$Proxy235'
at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1800) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1777) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1340) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1294) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.resolveArgument(AutowiredInstantiationArgumentsResolver.java:302) ~[na:na]
at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.resolveArguments(AutowiredInstantiationArgumentsResolver.java:232) ~[na:na]
at org.springframework.beans.factory.aot.AutowiredInstantiationArgumentsResolver.resolve(AutowiredInstantiationArgumentsResolver.java:154) ~[na:na]
at com.example.methodsecurity.MainController__BeanDefinitions.getMainControllerInstance(MainController__BeanDefinitions.java:30) ~[na:na]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1223) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1209) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1156) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:566) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:930) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:926) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:592) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:729) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:428) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[security-method:3.0.0-SNAPSHOT]
at com.example.methodsecurity.MethodSecurityApplication.main(MethodSecurityApplication.java:19) ~[security-method:0.0.1-SNAPSHOT]
It runs fine in AOT only.
To Reproduce:
Run the build.sh
script from this sample.
Comment From: sbrannen
@marcusdacoregio, why are you registering both a JDK and a Class proxy in the else
block?
https://github.com/marcusdacoregio/spring-native/blob/0c96a5ef43e5eb54b9bafec95992349f418da637/samples/security-method/src/main/java/com/example/methodsecurity/PrePostSecuredBeanRegistrationAotProcessor.java#L107-L108
What happens if you delete line 107 (registerJdkProxy
)?
Comment From: marcusdacoregio
Hi @sbrannen, if I remove that line the error changes to this:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'controller2': Proxy class defined by interfaces [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.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:611) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:930) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:926) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:592) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:729) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:428) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[security-method:3.0.0-SNAPSHOT]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[security-method:3.0.0-SNAPSHOT]
at com.example.methodsecurity.MethodSecurityApplication.main(MethodSecurityApplication.java:19) ~[security-method:0.0.1-SNAPSHOT]
Caused by: com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [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 com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:89) ~[na:na]
at com.oracle.svm.reflect.proxy.DynamicProxySupport.getProxyClass(DynamicProxySupport.java:158) ~[na:na]
at java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:48) ~[security-method:na]
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1037) ~[security-method:na]
at org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:126) ~[na:na]
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110) ~[na:na]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:480) ~[security-method:0.0.1-SNAPSHOT]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:344) ~[security-method:0.0.1-SNAPSHOT]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:293) ~[security-method:0.0.1-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:440) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1756) ~[security-method:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:604) ~[security-method:6.0.0-SNAPSHOT]
... 15 common frames omitted
Comment From: sbrannen
Thanks for trying it out and reporting back.
Both of the errors point to the same underlying issue.
The first error tells us that you got back a dynamic proxy instead of class-based proxy.
The second error tells us that a dynamic proxy could not be created for the interfaces SpringProxy,
Advised, and DecoratingProxy
, but Spring should never attempt to create a JDK dynamic proxy based solely on those three interfaces. Rather, the dynamic proxy must implement the user's interface(s) as well.
Controller2
does not implement any interfaces. So in order to proxy it for @PreAuthorize
support, Spring has to create a class-based proxy.
I have not debugged your application, but both of these errors point to org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(AdvisedSupport)
.
Specifically, if NativeDetector.inNativeImage()
returns true
, DefaultAopProxyFactory
will create a JdkDynamicAopProxy
instead of a ObjenesisCglibAopProxy
.
In summary, I think this is effectively a duplicate of #28115, but I will leave it open for @jhoeller to assess once he addresses #28115.
Comment From: snicoll
@marcusdacoregio please subscribe to #28115 and try again when it's fixed. If it turns out to be another issue, we can always reopen this one.