Again... method security with spring boot/security: Error creating bean with name 'methodSecurityInterceptor' "This object has already been built"
Solution 1
I want to thank M.Deinum. I finally got it working.
It is as simple as this:
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig {
@Configuration
@Order(1)
public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private DatabaseAuthenticationProvider databaseAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(databaseAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/usuario/*/rfc/*").authenticated()
...
Now my service method is accessible only by the specified role like this:
@Secured({Sec.R_ADMIN})
Usuario getUsuarioByEmisorAndIdUsuario(Emisor emisor, String idUsuario, boolean consultarRoles) throws AuthorizationException;
Being:
public class Sec {
public static final String R_ADMIN = "ROLE_ADMIN";
Solution 2
After several hours testing every option, it worked for me this way:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Bean
public AuthenticationManager authenticationManager(AuthenticationProvider provider) {
return new ProviderManager(Arrays.asList(provider));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// here your permissions
}
}
elysch
Updated on June 04, 2022Comments
-
elysch almost 2 years
I want to implement method security.
I'm facing a problem with @Secured and @PreAuth annotations. Whenever I add any of those to my service interface, I receive an exception like the following. Without them, my app runs just fine.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
It's a REST services application.
Here are some relevant parts of my config. Please let me know if I should add anything else.
@Configuration @EnableGlobalMethodSecurity(securedEnabled = true) public class WebSecurityConfig { ... @Autowired private DatabaseAuthenticationProvider databaseAuthenticationProvider; ... @Configuration @Order(1) public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { ... @Override protected void configure(HttpSecurity http) throws Exception { ... http .authorizeRequests() .antMatchers(HttpMethod.GET, "/usuario/*/rfc/*").authenticated() .antMatchers(HttpMethod.GET, "/usuario/*/rfc/*/").authenticated() .antMatchers(HttpMethod.GET, "/usuario/*").authenticated() .antMatchers(HttpMethod.GET, "/usuario/*/").authenticated() ... } } @SuppressWarnings("unchecked") @Bean public AuthenticationManager authenticationManager() throws Exception { return new AuthenticationManagerBuilder(new NopPostProcessor()).authenticationProvider(databaseAuthenticationProvider).build(); } @SuppressWarnings("rawtypes") private static class NopPostProcessor implements ObjectPostProcessor { @Override public Object postProcess(Object object) { return object; } }; @Bean public MessageDigestPasswordEncoder messageDigestPasswordEncoder() { return new MessageDigestPasswordEncoder("sha-256"); } }
And:
@Service("databaseAuthenticationProvider") public class DatabaseAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { private final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private MessageDigestPasswordEncoder messageDigestPasswordEncoder; ... @Override protected void additionalAuthenticationChecks(UserDetails arg0, UsernamePasswordAuthenticationToken arg1) throws AuthenticationException { return; } @Override protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { // logger.debug("Inside retrieveUser"); String password = (String) authentication.getCredentials(); String encryptedPassword = ""; if (StringUtils.hasText(password)) { encryptedPassword = messageDigestPasswordEncoder.encodePassword(password, null); } //UserDetails user = null; String expectedPassword = null; List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); WebAuthenticationDetails wad = null; wad = (WebAuthenticationDetails) authentication.getDetails(); ... return new org.springframework.security.core.userdetails.User( username, password, true, // enabled true, // account not expired true, // credentials not expired true, // account not locked authorities); } ... }
According to AlreadyBuiltException documentation:
Thrown when AbstractSecurityBuilder.build() is two or more times.
But I can't find out why spring is doing that.
Any ponters would be greatly appreciated.
Thank you all.
Here I put some more CallStack
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'usuarioServiceImpl' defined in file [C:\Users\ely\Documents\Desarrollo\Spring\workspace-sts-3.5.1.RELEASE\ws-timbrado-backend\target\classes\mx\i4b\timbrado\service\entidades\UsuarioServiceImpl.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1017) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] ... 73 common frames omitted Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:597) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor.getAdvice(MethodSecurityMetadataSourceAdvisor.java:96) ~[spring-security-core-3.2.3.RELEASE.jar:3.2.3.RELEASE] at org.springframework.aop.aspectj.AspectJProxyUtils.isAspectJAdvice(AspectJProxyUtils.java:67) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.aop.aspectj.AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(AspectJProxyUtils.java:49) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.extendAdvisors(AspectJAwareAdvisorAutoProxyCreator.java:97) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:89) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:69) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:376) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:339) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:421) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1558) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] ... 82 common frames omitted Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] ... 101 common frames omitted Caused by: org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:42) ~[spring-security-config-3.2.3.RELEASE.jar:3.2.3.RELEASE] at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationManager(AuthenticationConfiguration.java:78) ~[spring-security-config-3.2.3.RELEASE.jar:3.2.3.RELEASE] at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.authenticationManager(GlobalMethodSecurityConfiguration.java:248) ~[spring-security-config-3.2.3.RELEASE.jar:3.2.3.RELEASE] at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor(GlobalMethodSecurityConfiguration.java:119) ~[spring-security-config-3.2.3.RELEASE.jar:3.2.3.RELEASE] at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerBySpringCGLIB$$d8bcec4.CGLIB$methodSecurityInterceptor$8(<generated>) ~[spring-core-4.0.3.RELEASE.jar:3.2.3.RELEASE] at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerBySpringCGLIB$$d8bcec4$$FastClassBySpringCGLIB$$42ba89ef.invoke(<generated>) ~[spring-core-4.0.3.RELEASE.jar:3.2.3.RELEASE] at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312) ~[spring-context-4.0.3.RELEASE.jar:4.0.3.RELEASE] at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerBySpringCGLIB$$d8bcec4.methodSecurityInterceptor(<generated>) ~[spring-core-4.0.3.RELEASE.jar:3.2.3.RELEASE] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_25] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_25] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_25] at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_25] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE] ... 102 common frames omitted
////// Update 1 //////
Based on @M.Dainum I removed my
authenticationManager
.Tried to define my
databaseAuthenticationProvider
in three ways (included in this post), but all resulted in the same NullPointerException upon authentication.java.lang.NullPointerException: null at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:147) ~[spring-security-core-3.2.3.RELEASE.jar:3.2.3.RELEASE]
ProviderManager.java:147:
if (!provider.supports(toTest)) {
- I don't think `provider` is null since I made sure my autowired `databaseAuthenticationProvider` wasn't.
- `toTest` comes from `authentication.getClass()`. It shouldn't be null. Right? (Not sure if I remotely understood the problem)
getProviders()
contins:[null, org.springframework.security.authentication.AnonymousAuthenticationProvider@490adcdf]
Made a mistake before: The provider is null. So the "Autowiriring" is not happenning.
I think this is because in order to use something like:
auth.authenticationProvider(databaseAuthenticationProvider);
,databaseAuthenticationProvider
should be static and that prevents the autowiring. Right?If I create it with "new", then afterwards the
messageDigestPasswordEncoder
is null, and so on.So... How should I solve this?
Op1:
@Configuration @Order(1) public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(databaseAuthenticationProvider); } @Override protected void configure(HttpSecurity http) throws Exception {
Op2:
@Configuration @Order(1) public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authenticationProvider(databaseAuthenticationProvider);
Op3:
@Configuration @EnableGlobalMethodSecurity(securedEnabled = true) public class WebSecurityConfig { @Autowired protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(databaseAuthenticationProvider); }
////// Update 2 //////
To "force" the "Autowiriring", tried to remove
@Autowire
from the attribute and add it to a setter method like this:public class WebSecurityConfig { private static DatabaseAuthenticationProvider databaseAuthenticationProvider; @Autowired public void setDatabaseAuthenticationProvider(DatabaseAuthenticationProvider databaseAuthenticationProvider) { WebSecurityConfig.databaseAuthenticationProvider = databaseAuthenticationProvider; } @Configuration @Order(1) public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { if (databaseAuthenticationProvider == null) { System.out.println("************************************************* databaseAuthenticationProvider es null"); } else { System.out.println("************************************************* databaseAuthenticationProvider NO ES NULL"); } auth.authenticationProvider(databaseAuthenticationProvider); }
And now: back to squere one:
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
I guess the problem wasnt that I had my own
AuthenticationManager
Somehwere else is being built twice.How to find it?
By the way... it still has null value:
************************************************* databaseAuthenticationProvider es null