-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve warning message #15538
Improve warning message #15538
Conversation
Hey @quaff , thanks for the pull request. I'm trying to understand the underlying issue. For reference, the reasons for existing warnings have been documented in the issue gh-14663 . We want to help users realize why their The point of this PR is "there should be as many The case when there are multiple
Is this correct? In any case, the conditional "number of UserDetailsService == number of AbstractUserDetailsAuthProvider" is too broad. You'd need to validate that these beans actually depend on each other. That's a heavy lift for a simple log message. |
Exactly.
I tried, but
The warning message make me nervous. |
That's by design, I think. One workaround could be to obtain the bean dependencies' from the context's
I see. One workaround could be to provide EITHER |
@Bean
CustomAuthenticationManager authenticationManager(List<AuthenticationProvider> providers) {
return new CustomAuthenticationManager(providers);
}
@Bean
CustomAuthenticationProvider daoAuthenticationProvider(ObjectProvider<UserDetailsService> userDetailsService,
ObjectProvider<PasswordEncoder> passwordEncoder,
ObjectProvider<UserDetailsPasswordService> userDetailsPasswordService) {
UserDetailsService uds = userDetailsService.getIfAvailable(() -> username -> {
throw new UsernameNotFoundException(username);
});
CustomDaoAuthenticationProvider provider = new CustomDaoAuthenticationProvider();
provider.setUserDetailsService(uds);
passwordEncoder.ifAvailable(provider::setPasswordEncoder);
userDetailsPasswordService.ifAvailable(provider::setUserDetailsPasswordService);
return provider;
} |
I don't know about the specifics of your app, but everything you're doing here should be automatically handled by See Lines 92 to 107 in 3117fef
Does that work for you? |
No, I have customized |
I'll try and take a stab at this using the Depending on what you do with your // This UserService class does NOT implement UserDetailsService
class UserService {
private UserDetails loadUser(String username) throws UsernameNotFoundException {
// TODO
}
public UserDetailsService getUserDetailsService() {
return this::loadUser;
}
// + your own user operations, not necessarily matching UserDetailsManager
// You can also leverage an existing UserDetailsManager if you want
private UserDetailsManager userDetailsManager;
public void newUser(String username, String password, LocalDate birthDate) {
userDetailsManager.createUser(new CustomUser(...));
}
}
// and therefore you can decouple the interfaces ; one for business needs, one for Spring Security
@Bean
public UserService userService() {
return new UserService();
}
@Bean
public UserDetailsService userDetailsService(UserService userService) {
return userService.getUserDetailsService();
} It's a workaround, not great, but it will make the warnings go away. On the general theme of Global authentication, where these Hopefully, all these workarounds will eventually go away. |
How about List<BeanWithName<AbstractUserDetailsAuthenticationProvider>> userDetailsAuthenticationProviders = getBeansWithName(
AbstractUserDetailsAuthenticationProvider.class);
List<BeanWithName<AuthenticationManager>> authenticationManagers = getBeansWithName(AuthenticationManager.class);
boolean shouldWarn = userDetailsAuthenticationProviders.size() == 1
&& userDetailsAuthenticationProviders.getFirst().getBean().getClass().getName().startsWith("org.springframework.security.")
&& authenticationManagers.size() == 1
&& authenticationManagers.getFirst().getBean().getClass().getName().startsWith("org.springframework.security."); |
Why do you suggesting finding While decent, the String userDetailsServiceBeanName = userDetailsServices.get(0).getName();
if (auth.isConfigured()) {
if (isUserDetailsServiceUnused(userDetailsServiceBeanName)) {
this.logger.warn("Global AuthenticationManager configured with an AuthenticationProvider bean. "
+ "UserDetailsService beans will not be used for username/password login. "
+ "Consider removing the AuthenticationProvider bean. "
+ "Alternatively, consider using the UserDetailsService in a manually instantiated "
+ "DaoAuthenticationProvider.");
}
return;
}
// with:
private boolean isUserDetailsServiceUnused(String userDetailsServiceBeanName) {
var authProviderBeans = getBeansWithName(AbstractUserDetailsAuthenticationProvider.class);
if (authProviderBeans.isEmpty()) {
// this never happens
return true;
}
if (InitializeUserDetailsBeanManagerConfigurer.this.context instanceof ConfigurableApplicationContext ctx) {
var dependencies = ctx.getBeanFactory().getDependenciesForBean(authProviderBeans.get(0).getName());
return !Arrays.asList(dependencies).contains(userDetailsServiceBeanName);
}
return true;
} But, as I mentioned earlier, this is a lot of code. |
Hey @quaff - I've circled back with the team. We feel it's a bit too much complexity for a simple "UX" log line, so we will not be making code changes here. We value your feedback and we want to improve the logger message. Feel free to update your PR with an improved warning message, and we'll happily take it in. Something like:
In addition to improving the error message, if you feel strongly about this log message, please open an issue. It will allow us to see how the community reacts to the issue. For future reference, the easiest workaround is to increase the logger level:
Caveat: This logger is not part of our public API, and might change in the future. |
UserDetailsAuthenticationProvider
is configured per UserDetailsService
@Kehrlann I revised message from your suggestion, since not every application uses Spring Boot. |
Good point, thanks! |
We should assume that every
UserDetailsService
is wired with configuredUserDetailsAuthenticationProvider
.Continuation of commit 7ddc005