Spring Security 5 – My custom UserDetailsService is not called



I have found several questions about similar problems but none of them is exactly my case.

I am using the following class to configure the authentication/authorization in my application (a REST API).

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .csrf().disable()
            .authorizeRequests()
            .and()
            .exceptionHandling(e -> e
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
            )
            .antMatcher("/application-api/v1/**").authorizeRequests()
            .antMatchers("/application-api/v1/non-protected").permitAll()
            .anyRequest()
                .authenticated()
            .and()
            .oauth2ResourceServer()
            .opaqueToken();
    }

    @Override
    protected UserDetailsService userDetailsService() {
        return new ApplicationUserDetailsService();
    }
}

No matter what I try, my custom ApplicationUserDetailsService is never used. Can anyone see what is wrong with this configuration?

I have also tried to specify the following bean:

@Service
public class ApplicationUserDetailsService implements UserDetailsService {
    private static final Logger logger = LoggerFactory.getLogger(ApplicationUserDetailsService.class);
    public ApplicationUserDetailsService() {
        logger.debug("Creating instance of ApplicationUserDetailsService");
    }
    @Override
    public UserDetails loadUserByUsername(String userName) {
        logger.debug("Creating user details for {}", userName);

        return new ApplicationUser(userName);
    }
}

It did not work either.

########### UPDATE ###########

I have modified my SecurityConfiguration as follows:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);

    @Qualifier("applicationUserDetailsService")
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        logger.info("Oauth2 enabled: {}", enabled);
        httpSecurity.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .csrf().disable()
            .exceptionHandling(e -> e
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
            )
            .antMatcher("/application-api/v1/**").authorizeRequests()
            .antMatchers("/", "/application-api/unprotected").permitAll()
            .anyRequest()
                .authenticated()
            .and()
            .oauth2ResourceServer()
            .opaqueToken();
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());
    }

    @Bean(name="passwordEncoder")
    public PasswordEncoder passwordencoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected UserDetailsService userDetailsService() {
        return userDetailsService;
    }
}

I can see that my instance is used in the configuration, but nevertheless it is never called.

Answer

The problem is not with the injection of the bean. Given that you are seeing the expected bean injected, the reason is probably that the service is not used.

You need to check what authentication provider you are using. With the default providers, the service is used only if you your authentication provider is based on username and password.

See for example the Spring documentation:

https://docs.spring.io/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/core/userdetails/UserDetailsService.html

The following article describes how to customise the user details.

https://docs.spring.io/spring-security/site/docs/5.2.x/reference/html/oauth2.html#oauth2login-advanced-oauth2-user-service



Source: stackoverflow