Spring Webflux + Spring X509 证书验证问题的安全性:x509.X509CertImpl 无法转换为 class java.lang.String
Spring Webflux + Spring Security for X509 certificate validation issue: x509.X509CertImpl cannot be cast to class java.lang.String
我遇到了 Spring 安全性 + Spring Webflux + 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 and java.lang.String are in module java.base of loader 'bootstrap'”是什么意思,我是怎么结束的这个问题,请问如何解决?
谢谢
问题是 AbstractUserDetailsReactiveAuthenticationManager
旨在验证 username/password 而不是 X509 证书,因此它试图将 X509 凭证转换为字符串以像验证密码一样验证它。
相反,删除 ReactiveAuthenticationManager
Bean 并允许使用从 ReactiveUserDetailsService
bean 自动创建的默认值 ReactivePreAuthenticatedAuthenticationManager
。 SubjectDnX509PrincipalExtractor
是默认的,所以不需要显式提供,但是如果你需要自定义它,只需将它作为一个 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());
}
}
找到完整的样本
我遇到了 Spring 安全性 + Spring Webflux + 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 and java.lang.String are in module java.base of loader 'bootstrap'”是什么意思,我是怎么结束的这个问题,请问如何解决?
谢谢
问题是 AbstractUserDetailsReactiveAuthenticationManager
旨在验证 username/password 而不是 X509 证书,因此它试图将 X509 凭证转换为字符串以像验证密码一样验证它。
相反,删除 ReactiveAuthenticationManager
Bean 并允许使用从 ReactiveUserDetailsService
bean 自动创建的默认值 ReactivePreAuthenticatedAuthenticationManager
。 SubjectDnX509PrincipalExtractor
是默认的,所以不需要显式提供,但是如果你需要自定义它,只需将它作为一个 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());
}
}
找到完整的样本