jmix-framework / jmix

Jmix framework
https://www.jmix.io
Apache License 2.0
561 stars 118 forks source link

Cannot define own PasswordEncoder if project uses Authorization Server #2374

Closed knstvk closed 10 months ago

knstvk commented 11 months ago

Jmix 2.0.2 Steps to reproduce:

  1. Define primary bean in @SpringBootApplication class:
    @Bean
    @Primary
    PasswordEncoder myPasswordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
  2. Add REST add-on

The application fails to start:

Method authorizationServerSecurityFilterChain in io.jmix.autoconfigure.authserver.AuthServerAutoConfiguration$AuthorizationServerSecurityConfiguration required a single bean, but 2 were found:
    - myPasswordEncoder: defined by method 'myPasswordEncoder' in com.company.demo.DemoApplication
    - sec_PasswordEncoder: defined by method 'getPasswordEncoder' in class path resource [io/jmix/security/SecurityConfiguration.class]

Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
gorbunkov commented 11 months ago

It seems that the problem is that inside the org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2ClientAuthenticationConfigurer#createDefaultAuthenticationProviders the PasswordEncoder instance is obtained with a helper method:

PasswordEncoder passwordEncoder = OAuth2ConfigurerUtils.getOptionalBean(httpSecurity, PasswordEncoder.class);

This helper method doesn't consider the @Primary annotation.

The solution may be to move the PasswordEncoder bean declaration from a regular spring configuration to security auto-configuration with a @ConditionalOnMissingBean annotation. Then we'll be sure that only one instance of PasswordEncoder is registered at a time.