Skip to content

Commit 7ddc005

Browse files
Kehrlannjzheaux
authored andcommitted
Improve logging for Global Authentication
Closes gh-14663
1 parent 23dc0ed commit 7ddc005

File tree

2 files changed

+129
-4
lines changed

2 files changed

+129
-4
lines changed

config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/InitializeAuthenticationProviderBeanManagerConfigurer.java

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,15 @@
1616

1717
package org.springframework.security.config.annotation.authentication.configuration;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.apache.commons.logging.Log;
23+
import org.apache.commons.logging.LogFactory;
24+
1925
import org.springframework.context.ApplicationContext;
2026
import org.springframework.core.annotation.Order;
27+
import org.springframework.core.log.LogMessage;
2128
import org.springframework.security.authentication.AuthenticationProvider;
2229
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
2330

@@ -49,16 +56,33 @@ public void init(AuthenticationManagerBuilder auth) throws Exception {
4956

5057
class InitializeAuthenticationProviderManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
5158

59+
private final Log logger = LogFactory.getLog(getClass());
60+
5261
@Override
5362
public void configure(AuthenticationManagerBuilder auth) {
5463
if (auth.isConfigured()) {
5564
return;
5665
}
57-
AuthenticationProvider authenticationProvider = getBeanOrNull(AuthenticationProvider.class);
58-
if (authenticationProvider == null) {
66+
List<BeanWithName<AuthenticationProvider>> authenticationProviders = getBeansWithName(
67+
AuthenticationProvider.class);
68+
if (authenticationProviders.isEmpty()) {
5969
return;
6070
}
71+
else if (authenticationProviders.size() > 1) {
72+
List<String> beanNames = authenticationProviders.stream().map(BeanWithName::getName).toList();
73+
this.logger.info(LogMessage.format("Found %s AuthenticationProvider beans, with names %s. "
74+
+ "Global Authentication Manager will not be configured with AuthenticationProviders. "
75+
+ "Consider publishing a single AuthenticationProvider bean, or wiring your Providers directly "
76+
+ "using the DSL.", authenticationProviders.size(), beanNames));
77+
return;
78+
}
79+
var authenticationProvider = authenticationProviders.get(0).getBean();
80+
var authenticationProviderBeanName = authenticationProviders.get(0).getName();
81+
6182
auth.authenticationProvider(authenticationProvider);
83+
this.logger.info(LogMessage.format(
84+
"Global AuthenticationManager configured with AuthenticationProvider bean with name %s",
85+
authenticationProviderBeanName));
6286
}
6387

6488
/**
@@ -74,6 +98,42 @@ private <T> T getBeanOrNull(Class<T> type) {
7498
return InitializeAuthenticationProviderBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
7599
}
76100

101+
/**
102+
* @return a list of beans of the requested class, along with their names. If
103+
* there are no registered beans of that type, the list is empty.
104+
*/
105+
private <T> List<BeanWithName<T>> getBeansWithName(Class<T> type) {
106+
List<BeanWithName<T>> beanWithNames = new ArrayList<>();
107+
String[] beanNames = InitializeAuthenticationProviderBeanManagerConfigurer.this.context
108+
.getBeanNamesForType(type);
109+
for (String beanName : beanNames) {
110+
T bean = InitializeAuthenticationProviderBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
111+
beanWithNames.add(new BeanWithName<T>(bean, beanName));
112+
}
113+
return beanWithNames;
114+
}
115+
116+
static class BeanWithName<T> {
117+
118+
private final T bean;
119+
120+
private final String name;
121+
122+
BeanWithName(T bean, String name) {
123+
this.bean = bean;
124+
this.name = name;
125+
}
126+
127+
T getBean() {
128+
return this.bean;
129+
}
130+
131+
String getName() {
132+
return this.name;
133+
}
134+
135+
}
136+
77137
}
78138

79139
}

config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/InitializeUserDetailsBeanManagerConfigurer.java

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,16 @@
1616

1717
package org.springframework.security.config.annotation.authentication.configuration;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.apache.commons.logging.Log;
23+
import org.apache.commons.logging.LogFactory;
24+
1925
import org.springframework.context.ApplicationContext;
2026
import org.springframework.core.Ordered;
2127
import org.springframework.core.annotation.Order;
28+
import org.springframework.core.log.LogMessage;
2229
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
2330
import org.springframework.security.authentication.password.CompromisedPasswordChecker;
2431
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@@ -55,15 +62,35 @@ public void init(AuthenticationManagerBuilder auth) throws Exception {
5562

5663
class InitializeUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
5764

65+
private final Log logger = LogFactory.getLog(getClass());
66+
5867
@Override
5968
public void configure(AuthenticationManagerBuilder auth) throws Exception {
69+
List<BeanWithName<UserDetailsService>> userDetailsServices = getBeansWithName(UserDetailsService.class);
6070
if (auth.isConfigured()) {
71+
if (!userDetailsServices.isEmpty()) {
72+
this.logger.warn("Global AuthenticationManager configured with an AuthenticationProvider bean. "
73+
+ "UserDetailsService beans will not be used for username/password login. "
74+
+ "Consider removing the AuthenticationProvider bean. "
75+
+ "Alternatively, consider using the UserDetailsService in a manually instantiated "
76+
+ "DaoAuthenticationProvider.");
77+
}
78+
return;
79+
}
80+
81+
if (userDetailsServices.isEmpty()) {
6182
return;
6283
}
63-
UserDetailsService userDetailsService = getBeanOrNull(UserDetailsService.class);
64-
if (userDetailsService == null) {
84+
else if (userDetailsServices.size() > 1) {
85+
List<String> beanNames = userDetailsServices.stream().map(BeanWithName::getName).toList();
86+
this.logger.warn(LogMessage.format("Found %s UserDetailsService beans, with names %s. "
87+
+ "Global Authentication Manager will not use a UserDetailsService for username/password login. "
88+
+ "Consider publishing a single UserDetailsService bean.", userDetailsServices.size(),
89+
beanNames));
6590
return;
6691
}
92+
var userDetailsService = userDetailsServices.get(0).getBean();
93+
var userDetailsServiceBeanName = userDetailsServices.get(0).getName();
6794
PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
6895
UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
6996
CompromisedPasswordChecker passwordChecker = getBeanOrNull(CompromisedPasswordChecker.class);
@@ -83,6 +110,9 @@ public void configure(AuthenticationManagerBuilder auth) throws Exception {
83110
}
84111
provider.afterPropertiesSet();
85112
auth.authenticationProvider(provider);
113+
this.logger.info(LogMessage.format(
114+
"Global AuthenticationManager configured with UserDetailsService bean with name %s",
115+
userDetailsServiceBeanName));
86116
}
87117

88118
/**
@@ -97,6 +127,41 @@ private <T> T getBeanOrNull(Class<T> type) {
97127
return InitializeUserDetailsBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
98128
}
99129

130+
/**
131+
* @return a list of beans of the requested class, along with their names. If
132+
* there are no registered beans of that type, the list is empty.
133+
*/
134+
private <T> List<BeanWithName<T>> getBeansWithName(Class<T> type) {
135+
List<BeanWithName<T>> beanWithNames = new ArrayList<>();
136+
String[] beanNames = InitializeUserDetailsBeanManagerConfigurer.this.context.getBeanNamesForType(type);
137+
for (String beanName : beanNames) {
138+
T bean = InitializeUserDetailsBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
139+
beanWithNames.add(new BeanWithName<T>(bean, beanName));
140+
}
141+
return beanWithNames;
142+
}
143+
144+
static class BeanWithName<T> {
145+
146+
private final T bean;
147+
148+
private final String name;
149+
150+
BeanWithName(T bean, String name) {
151+
this.bean = bean;
152+
this.name = name;
153+
}
154+
155+
T getBean() {
156+
return this.bean;
157+
}
158+
159+
String getName() {
160+
return this.name;
161+
}
162+
163+
}
164+
100165
}
101166

102167
}

0 commit comments

Comments
 (0)