Spring Webflux + Spring Security for X509 证书验证问题:x509.X509C



我遇到了Spring Security + SpringWebflux+ X509客户端证书验证的问题。 我可以得到一些帮助吗?

使用下面的最小工作代码:

@RestController
@SpringBootApplication
public class X509AuthenticationServer {
public static void main(String[] args) {
SpringApplication.run(X509AuthenticationServer.class, args);
}
@RequestMapping(value = "/test")
public Mono<String> test() {
return Mono.just("n test n");
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity serverHttpSecurity, UserDetailsRepositoryReactiveAuthenticationManager authenticationManager, X509PrincipalExtractor principalExtractor) {
return serverHttpSecurity.authorizeExchange().anyExchange().authenticated().and().x509().principalExtractor(principalExtractor).authenticationManager(authenticationManager).and().build();
}
@Bean
public X509PrincipalExtractor principalExtractor() {
return new SubjectDnX509PrincipalExtractor();
}
@Bean
public UserDetailsRepositoryReactiveAuthenticationManager authenticationManager(ReactiveUserDetailsService reactiveUserDetailsService) {
return new UserDetailsRepositoryReactiveAuthenticationManager(reactiveUserDetailsService);
}
@Bean
public MapReactiveUserDetailsService mapReactiveUserDetailsService() {
return new MapReactiveUserDetailsService(User.withUsername("USER").authorities(new SimpleGrantedAuthority("USER")).password("").build());
}
}
server.ssl.key-store=/keystore.jks
server.ssl.key-store-password=123456
server.ssl.key-alias=localhost
server.ssl.key-password=123456
server.ssl.enabled=true
server.ssl.trust-store=/truststore.jks
server.ssl.trust-store-password=123456
server.ssl.client-auth=need
server.port=8443
spring.security.user.name=test
spring.security.user.password=test
logging.level.root=DEBUG

我希望这能起作用,即我可以进行 X509 证书验证。 但是,我面临着这个我不理解的相当奇怪的例外

2020-10-15 20:04:57.773 DEBUG [,9dfd3873894ac7fe,9dfd3873894ac7fe,true] 8646 --- [ctor-http-nio-3] .w.a.p.x.SubjectDnX509PrincipalExtractor : Subject DN is 'CN=(I see the correct CN), OU=zzzzzz, OU=xxxxxx, O=cccccc, C=US'
2020-10-15 20:04:57.773 DEBUG [,9dfd3873894ac7fe,9dfd3873894ac7fe,true] 8646 --- [ctor-http-nio-3] .w.a.p.x.SubjectDnX509PrincipalExtractor : Extracted Principal name is(I see the correct CN)
2020-10-15 20:04:57.785 DEBUG [,9dfd3873894ac7fe,9dfd3873894ac7fe,true] 8646 --- [ctor-http-nio-3] a.w.r.e.AbstractErrorWebExceptionHandler : [a8f68710/1-1] Resolved [ClassCastException: class sun.security.x509.X509CertImpl cannot be cast to class java.lang.String (sun.security.x509.X509CertImpl and java.lang.String are in module java.base of loader 'bootstrap')] for HTTP GET /test
2020-10-15 20:04:57.786 ERROR [,9dfd3873894ac7fe,9dfd3873894ac7fe,true] 8646 --- [ctor-http-nio-3] a.w.r.e.AbstractErrorWebExceptionHandler : [a8f68710/1-1]  500 Server Error for HTTP GET "/test
java.lang.ClassCastException: class sun.security.x509.X509CertImpl cannot be cast to class java.lang.String (sun.security.x509.X509CertImpl and java.lang.String are in module java.base of loader 'bootstrap')
at org.springframework.security.authentication.AbstractUserDetailsReactiveAuthenticationManager.authenticate(AbstractUserDetailsReactiveAuthenticationManager.java:99) ~[spring-security-core-5.3.4.RELEASE.jar:5.3.4.RELEASE]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
|_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain]

问:这个"sun.security.x509.X509CertImpl和java.lang.String在加载程序'bootstrap'的模块java.base中"是什么意思,我是如何解决这个问题的,以及如何解决它?

谢谢

问题是AbstractUserDetailsReactiveAuthenticationManager旨在验证用户名/密码而不是 X509 证书,因此它尝试将 X509 凭据强制转换为字符串以像密码一样对其进行验证。

相反,请删除ReactiveAuthenticationManagerBean,并允许使用从ReactiveUserDetailsServiceBean 自动创建的默认ReactivePreAuthenticatedAuthenticationManagerSubjectDnX509PrincipalExtractor是默认的,因此无需显式提供它,但是如果您需要自定义它,只需将其公开为 Bean,默认情况下就会使用它。

@RestController
@SpringBootApplication
public class X509AuthenticationServer {
public static void main(String[] args) {
SpringApplication.run(X509AuthenticationServer.class, args);
}
@RequestMapping(value = "/test")
public Mono<String> test() {
return Mono.just("n test n");
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// @formatter:off
http
.authorizeExchange()
.anyExchange().authenticated()
.and()
.x509();
// @formatter:on
return http.build();
}
@Bean
public MapReactiveUserDetailsService mapReactiveUserDetailsService() {
return new MapReactiveUserDetailsService(User.withUsername("USER").authorities("USER").password("").build());
}
}

您还可以在 https://github.com/spring-projects/spring-security-samples/blob/592e4f89d2819f255340518a2c91b7e6eab6ed3e/reactive/webflux/java/authentication/x509/src/main/java/example/WebfluxX509Application.java 中找到完整的示例

最新更新