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)) {
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
AuthenticationManagerBuilder is a helper class that eases the set up of UserDetailService, AuthenticationProvider, and other dependencies to build an AuthenticationManager. For a global AuthenticationManager, we should define an AuthenticationManager as a bean.
configure. Deprecated. Used by the default implementation of authenticationManager() to attempt to obtain an AuthenticationManager . If overridden, the AuthenticationManagerBuilder should be used to specify the AuthenticationManager .
For adding a Spring Boot Security to your Spring Boot application, we need to add the Spring Boot Starter Security dependency in our build configuration file. Maven users can add the following dependency in the pom. xml file. Gradle users can add the following dependency in the build.
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";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With