Improve logging for Global Authentication
Closes gh-14663
This commit is contained in:
parent
23dc0edb97
commit
7ddc00521e
|
@ -16,8 +16,15 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.authentication.configuration;
|
package org.springframework.security.config.annotation.authentication.configuration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.core.log.LogMessage;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
|
||||||
|
@ -49,16 +56,33 @@ class InitializeAuthenticationProviderBeanManagerConfigurer extends GlobalAuthen
|
||||||
|
|
||||||
class InitializeAuthenticationProviderManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
|
class InitializeAuthenticationProviderManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
|
||||||
|
|
||||||
|
private final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(AuthenticationManagerBuilder auth) {
|
public void configure(AuthenticationManagerBuilder auth) {
|
||||||
if (auth.isConfigured()) {
|
if (auth.isConfigured()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AuthenticationProvider authenticationProvider = getBeanOrNull(AuthenticationProvider.class);
|
List<BeanWithName<AuthenticationProvider>> authenticationProviders = getBeansWithName(
|
||||||
if (authenticationProvider == null) {
|
AuthenticationProvider.class);
|
||||||
|
if (authenticationProviders.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (authenticationProviders.size() > 1) {
|
||||||
|
List<String> beanNames = authenticationProviders.stream().map(BeanWithName::getName).toList();
|
||||||
|
this.logger.info(LogMessage.format("Found %s AuthenticationProvider beans, with names %s. "
|
||||||
|
+ "Global Authentication Manager will not be configured with AuthenticationProviders. "
|
||||||
|
+ "Consider publishing a single AuthenticationProvider bean, or wiring your Providers directly "
|
||||||
|
+ "using the DSL.", authenticationProviders.size(), beanNames));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var authenticationProvider = authenticationProviders.get(0).getBean();
|
||||||
|
var authenticationProviderBeanName = authenticationProviders.get(0).getName();
|
||||||
|
|
||||||
auth.authenticationProvider(authenticationProvider);
|
auth.authenticationProvider(authenticationProvider);
|
||||||
|
this.logger.info(LogMessage.format(
|
||||||
|
"Global AuthenticationManager configured with AuthenticationProvider bean with name %s",
|
||||||
|
authenticationProviderBeanName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,6 +98,42 @@ class InitializeAuthenticationProviderBeanManagerConfigurer extends GlobalAuthen
|
||||||
return InitializeAuthenticationProviderBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
|
return InitializeAuthenticationProviderBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a list of beans of the requested class, along with their names. If
|
||||||
|
* there are no registered beans of that type, the list is empty.
|
||||||
|
*/
|
||||||
|
private <T> List<BeanWithName<T>> getBeansWithName(Class<T> type) {
|
||||||
|
List<BeanWithName<T>> beanWithNames = new ArrayList<>();
|
||||||
|
String[] beanNames = InitializeAuthenticationProviderBeanManagerConfigurer.this.context
|
||||||
|
.getBeanNamesForType(type);
|
||||||
|
for (String beanName : beanNames) {
|
||||||
|
T bean = InitializeAuthenticationProviderBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
|
||||||
|
beanWithNames.add(new BeanWithName<T>(bean, beanName));
|
||||||
|
}
|
||||||
|
return beanWithNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BeanWithName<T> {
|
||||||
|
|
||||||
|
private final T bean;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
BeanWithName(T bean, String name) {
|
||||||
|
this.bean = bean;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
T getBean() {
|
||||||
|
return this.bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,16 @@
|
||||||
|
|
||||||
package org.springframework.security.config.annotation.authentication.configuration;
|
package org.springframework.security.config.annotation.authentication.configuration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.core.log.LogMessage;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.authentication.password.CompromisedPasswordChecker;
|
import org.springframework.security.authentication.password.CompromisedPasswordChecker;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
@ -55,15 +62,35 @@ class InitializeUserDetailsBeanManagerConfigurer extends GlobalAuthenticationCon
|
||||||
|
|
||||||
class InitializeUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
|
class InitializeUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
|
||||||
|
|
||||||
|
private final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
List<BeanWithName<UserDetailsService>> userDetailsServices = getBeansWithName(UserDetailsService.class);
|
||||||
if (auth.isConfigured()) {
|
if (auth.isConfigured()) {
|
||||||
|
if (!userDetailsServices.isEmpty()) {
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
UserDetailsService userDetailsService = getBeanOrNull(UserDetailsService.class);
|
|
||||||
if (userDetailsService == null) {
|
if (userDetailsServices.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (userDetailsServices.size() > 1) {
|
||||||
|
List<String> beanNames = userDetailsServices.stream().map(BeanWithName::getName).toList();
|
||||||
|
this.logger.warn(LogMessage.format("Found %s UserDetailsService beans, with names %s. "
|
||||||
|
+ "Global Authentication Manager will not use a UserDetailsService for username/password login. "
|
||||||
|
+ "Consider publishing a single UserDetailsService bean.", userDetailsServices.size(),
|
||||||
|
beanNames));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var userDetailsService = userDetailsServices.get(0).getBean();
|
||||||
|
var userDetailsServiceBeanName = userDetailsServices.get(0).getName();
|
||||||
PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
|
PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
|
||||||
UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
|
UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
|
||||||
CompromisedPasswordChecker passwordChecker = getBeanOrNull(CompromisedPasswordChecker.class);
|
CompromisedPasswordChecker passwordChecker = getBeanOrNull(CompromisedPasswordChecker.class);
|
||||||
|
@ -83,6 +110,9 @@ class InitializeUserDetailsBeanManagerConfigurer extends GlobalAuthenticationCon
|
||||||
}
|
}
|
||||||
provider.afterPropertiesSet();
|
provider.afterPropertiesSet();
|
||||||
auth.authenticationProvider(provider);
|
auth.authenticationProvider(provider);
|
||||||
|
this.logger.info(LogMessage.format(
|
||||||
|
"Global AuthenticationManager configured with UserDetailsService bean with name %s",
|
||||||
|
userDetailsServiceBeanName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,6 +127,41 @@ class InitializeUserDetailsBeanManagerConfigurer extends GlobalAuthenticationCon
|
||||||
return InitializeUserDetailsBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
|
return InitializeUserDetailsBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a list of beans of the requested class, along with their names. If
|
||||||
|
* there are no registered beans of that type, the list is empty.
|
||||||
|
*/
|
||||||
|
private <T> List<BeanWithName<T>> getBeansWithName(Class<T> type) {
|
||||||
|
List<BeanWithName<T>> beanWithNames = new ArrayList<>();
|
||||||
|
String[] beanNames = InitializeUserDetailsBeanManagerConfigurer.this.context.getBeanNamesForType(type);
|
||||||
|
for (String beanName : beanNames) {
|
||||||
|
T bean = InitializeUserDetailsBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
|
||||||
|
beanWithNames.add(new BeanWithName<T>(bean, beanName));
|
||||||
|
}
|
||||||
|
return beanWithNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BeanWithName<T> {
|
||||||
|
|
||||||
|
private final T bean;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
BeanWithName(T bean, String name) {
|
||||||
|
this.bean = bean;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
T getBean() {
|
||||||
|
return this.bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue