In previous Spring versions, bean overriding was allowed, but Spring 5 brings disabling by default. Its OK, but not for creating custom methodSecurityMetadataSource definition. I use it for custom annotation defining rules for authorization.
When I override customMethodSecurityMetadataSource in my confuiguration extending GlobalMethodSecurityConfiguration, I get already defined exception:
org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; factoryMethodName=methodSecurityInterceptor; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]] for bean 'methodSecurityInterceptor': There is already ...
Used code to override:
/**
* Custom configuration of method level security.
*/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return new AuthorizeAnnotationSecurityMetadataSource();
}
}
There should be some configurer or looking for bean of instance MethodSecurityMetadataSource in method customMethodSecurityMetadataSource. Then it will be added to delegate with other sources:
https://github.com/spring-projects/spring-security/blob/5c2ee09bc3a0fe0a14b0aa86d1946542c4ca2aab/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java#L306
Or even @ConditionalOnMissingBean on beans defined in this configuration file will be enough to enable custom bean definition
Comment From: rwinch
Thanks for the report. To speed things up a bit can you put together a complete sample and post a link the the project?
Or even @ConditionalOnMissingBean on beans defined in this configuration file will be enough to enable custom bean definition
We cannot use conditionals in Spring Security's code base because that is a Boot dependency which Spring Security doesn't rely on.
Comment From: jkapec
Safe solution can be for example changing in bean initialization method methodSecurityMetadataSource to use new MethodSecurityMetadataSourceConfigurer:
public abstract class MethodSecurityMetadataSourceConfigurer {
public abstract MethodSecurityMetadataSource getApplicationMethodSecurityMetadataSource();
}
then it should like:
@Autowired(required=false)
private MethodSecurityMetadataSourceConfigurer metadataSourceConfigurer;
@Bean
public MethodSecurityMetadataSource methodSecurityMetadataSource() {
List<MethodSecurityMetadataSource> sources = new ArrayList<MethodSecurityMetadataSource>();
ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(
getExpressionHandler());
if (metadataSourceConfigurer != null && metadataSourceConfigurer.getApplicationMethodSecurityMetadataSource() != null) {
sources.add(metadataSourceConfigurer.getApplicationMethodSecurityMetadataSource());
}
MethodSecurityMetadataSource customMethodSecurityMetadataSource = customMethodSecurityMetadataSource();
...
}
If someone need to use own source, it is enough to create custom MethodSecurityMetadataSourceConfigurer bean.
Comment From: rwinch
@jkapec Do you have a complete sample that reproduces the issue?
Comment From: SparkMonkey
I used the following code as work around :
@ComponentScan(basePackages = {"foo.bar"}, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = GlobalMethodSecurityConfiguration.class))`
public class BarApplication {
public static void main(String[] args) {
SpringApplication.run(NeovaBanqueApplication.class, args);
}
}
So i can do the following without trouble :
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
BarMethodSecurityExpressionHandler expressionHandler = new BarMethodSecurityExpressionHandler();
// expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
}
Comment From: ieugen
I've also encountered this issue while configuring a custom permission evaluator.
Comment From: rwinch
Note: We are still waiting on a complete sample to reproduce the problem.
Comment From: SparkMonkey
What do you mean by a complete sample ? You mean an entire project ? How ?
I can do it. It's just an empty spring boot 2.1.4 project, with spring security and the code in previous comments.
Like this :
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
// DO SPECIFIC STUFF
return expressionHandler;
}
}
The point is bean overriding is not allowed anymore by default. GlobalMethodSecurityConfiguration is a @Component and when you extends it you want your version to be a @Component too. So it's a been overriding.
Comment From: rwinch
I can do it. It's just an empty spring boot 2.1.4 project, with spring security and the code in previous
Thanks that would be very much appreciated.
NOTE: While it seems trivial to ask for the Spring Security team to create the sample, it is important to remember that all the little things we do adds up. The team is much smaller in size than the community, so we ask for help when issues are submitted. For these reasons, we prioritize issues that have complete samples.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: Tugdual
I had the same problem on my project. It's not with Spring Boot, but if it can help...
My custom config was ignore because another GlobalSecurityMethodConfiguration was imported before.
Everything worked just fine after removing the @Import(OtherCustomConfig.class) (an d merging it with my custom config)
Comment From: SparkMonkey
I failed to reproduce at home from a brand new project.
I'll retry on the environment on which the problem initially occured soon.
Comment From: martin-g
This issue is the same as https://github.com/Activiti/Activiti/issues/2387. There is a reproducer at https://github.com/rasheedamir/vouchers-service
Comment From: rwinch
Thanks for the sample to reproduce @martin-g! @jgrandja can you please take a look at this?
Comment From: martin-g
The reproduce is not really mine! I was just googling for the same issue, found both issues and decided to link them.
Comment From: jgrandja
@martin-g The sample you provided does not raise an exception on application startup. Also, the sample that @rwinch has requested should be an absolute minimal code sample that reproduces the issue - the sample you provided has quite a bit of code and dependencies.
As @rwinch has stated in this comment, we do require a minimal sample in order to efficiently troubleshoot and resolve. @jkapec Are you able to provide a sample?
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Comment From: H-Lo
Hi @jkapec, I had the same issue as you have. Finally I found I had used @EnableGlobalMethodSecurity 2 times. When removed one of those, the exception disappeared. I know you mentioned very simple project, but no harm to check. Also if anyone else comes here, it might help. BR, Hrvoje
Comment From: dekinnek
Hi all, I can confirm @H-Lo's solution that also was the source of my problem. I did add a custom MethodSecurityConfig with @EnableGlobalMethodSecurity for my project which already contained a WebSecurityConfigurerAdapter with said @EnableGlobalMethodSecurity annotation as well. By removing the latter the exception no longer occured.
Comment From: thomaslevans-wf
Hi @jkapec, I had the same issue as you have. Finally I found I had used @EnableGlobalMethodSecurity 2 times. When removed one of those, the exception disappeared. I know you mentioned very simple project, but no harm to check. Also if anyone else comes here, it might help. BR, Hrvoje
Can also confirm @H-Lo 's solution resolved this issue for me.