Spring Security:捕获Active Directory错误凭证的LDAP认证异常
Spring Boot集成Active Directory认证时错误凭证引发栈溢出问题
我正在用Spring Boot和Active Directory构建认证过滤器,当前配置代码如下:
@Configuration @EnableWebSecurity public class WebSecurityConfig { private static final String DOMAIN = "xxxxx.net"; private static final String URL = "ldap://xxxxxx:389/"; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable) .cors(cors -> cors .configurationSource(request -> { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedOrigins(List.of("http://localhost:4200")); corsConfiguration.setAllowedMethods(List.of("POST", "PUT", "GET", "DELETE", "OPTIONS")); corsConfiguration.setAllowedHeaders(List.of("Authorization", "Content-Type")); corsConfiguration.setAllowCredentials(true); return corsConfiguration; })) .authorizeHttpRequests(authorize -> authorize .requestMatchers("auth/**").permitAll() .anyRequest().authenticated()) .formLogin(login -> login.permitAll()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)); return http.build(); } @Bean public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { AuthenticationManagerBuilder auth = http.getSharedObject(AuthenticationManagerBuilder.class); ActiveDirectoryLdapAuthenticationProvider adProvider = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL); adProvider.setConvertSubErrorCodesToExceptions(true); adProvider.setUseAuthenticationRequestCredentials(true); auth.authenticationProvider(adProvider); return auth.build(); } }
使用Spring Security默认登录表单提交正确凭证时功能正常,但提交错误凭证时,控制台会出现无限循环的异常日志:
2024-06-22T01:56:14.121-05:00 DEBUG 19756 --- [waza] [nio-8080-exec-4] ctiveDirectoryLdapAuthenticationProvider : Authentication for fr@xxxxx.net failed:javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090439, comment: AcceptSecurityContext error, data 52e, v4563 ] 2024-06-22T01:56:14.123-05:00 INFO 19756 --- [waza] [nio-8080-exec-4] ctiveDirectoryLdapAuthenticationProvider : Active Directory authentication failed: Supplied password was invalid 2024-06-22T01:56:14.136-05:00 DEBUG 19756 --- [waza] [nio-8080-exec-4] ctiveDirectoryLdapAuthenticationProvider : Authentication for fr@xxxxxx.net failed:javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090439, comment: AcceptSecurityContext error, data 52e, v4563 ] 2024-06-22T01:56:14.136-05:00 INFO 19756 --- [waza] [nio-8080-exec-4] ctiveDirectoryLdapAuthenticationProvider : Active Directory authentication failed: Supplied password was invalid
最终会触发栈溢出错误:
2024-06-22T01:56:19.888-05:00 ERROR 19756 --- [waza] [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause java.lang.StackOverflowError: null at java.base/java.net.URI$Parser.scan(URI.java:3141) ~[na:na]
如何捕获该LDAP认证异常,防止栈溢出或终止错误操作?
解决方案
修改配置代码,将ActiveDirectoryLdapAuthenticationProvider单独提取为Bean,同时移除默认表单登录的permitAll()配置(这是触发无限循环的核心原因),修改后的代码如下:
@Configuration @EnableWebSecurity public class WebSecurityConfig { private static final String DOMAIN = "xxxxx.net"; private static final String URL = "ldap://xxxxxx:389/"; @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()) .cors(cors -> cors.configurationSource(request -> { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedOrigins(List.of("http://localhost:4200")); corsConfiguration.setAllowedMethods(List.of("POST", "PUT", "GET", "DELETE", "OPTIONS")); corsConfiguration.setAllowedHeaders(List.of("Authorization", "Content-Type")); corsConfiguration.setAllowCredentials(true); return corsConfiguration; })) .authorizeHttpRequests( authorize -> authorize.requestMatchers("auth/**").permitAll() .anyRequest().authenticated()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)); return http.build(); } @Bean AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { AuthenticationManagerBuilder auth = http.getSharedObject(AuthenticationManagerBuilder.class); ActiveDirectoryLdapAuthenticationProvider adProvider = authProvider(); auth.authenticationProvider(adProvider); return auth.build(); } @Bean ActiveDirectoryLdapAuthenticationProvider authProvider() { ActiveDirectoryLdapAuthenticationProvider adlap = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL); adlap.setUseAuthenticationRequestCredentials(true); adlap.setConvertSubErrorCodesToExceptions(true); return adlap; } }
说明:移除
formLogin(login -> login.permitAll())后,Spring Security会正确处理认证失败流程,避免无限循环;将认证提供者单独声明为Bean,确保其被Spring容器正确初始化和管理,从而正常捕获LDAP认证异常。
内容的提问来源于stack exchange,提问作者Francis
相关产品推荐
相关产品推荐

