我在 kuntes 集群上有带有 keycloak 集成的弹簧靴。在生产环境中,SSL 的 I 证书受信任,如"example.com"。我将我的 Spring 启动 Web 应用程序和 keycloak 配置为与入口位于同一域路由下,并提供 SSL 以在两台服务器上重用我的证书。
https://example.com -> 弹簧启动 https://example.com/auth ->钥匙斗篷
这工作正常,但是当我尝试通过 keycloak 弹簧适配器从我的 Web 应用程序获取令牌时,我在日志中收到以下错误:
message: "failed to turn code into token"
stack_trace: "s.s.p.c.SunCertPathBuilderException: unable to find valid certification path to requested target
at s.s.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at s.s.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
... 95 common frames omitted
Wrapped by: s.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
at sun.security.validator.Validator.validate(Validator.java:262)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:237)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
... 89 common frames omitted
Wrapped by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at o.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:570)
at o.keycloak.adapters.SniSSLSocketFactory.createLayeredSocket(SniSSLSocketFactory.java:114)
at o.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:554)
at o.keycloak.adapters.SniSSLSocketFactory.connectSocket(SniSSLSocketFactory.java:109)
at o.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:415)
at o.a.h.i.c.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at o.a.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144)
at o.a.h.i.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134)
at o.a.h.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:605)
at o.a.h.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:440)
at o.a.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)
at o.a.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at o.a.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
at o.a.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at org.keycloak.adapters.ServerRequest.invokeAccessCodeToToken(ServerRequest.java:111)
at o.k.adapters.OAuthRequestAuthenticator.resolveCode(OAuthRequestAuthenticator.java:335)
at o.k.adapters.OAuthRequestAuthenticator.authenticate(OAuthRequestAuthenticator.java:280)
at o.keycloak.adapters.RequestAuthenticator.authenticate(RequestAuthenticator.java:139)
at o.k.a.s.f.KeycloakAuthenticationProcessingFilter.attemptAuthentication(KeycloakAuthenticationProcessingFilter.java:150)
at o.s.s.w.a.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at o.s.s.w.a.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at o.k.a.s.f.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:86)
at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at o.s.s.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
at o.s.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at o.s.s.w.c.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at o.s.s.w.c.r.a.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at o.s.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at o.s.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at o.s.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at o.s.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
at o.s.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at o.a.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at o.a.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at o.s.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at o.s.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at o.a.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at o.a.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at o.s.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at o.s.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at o.a.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at o.a.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at o.s.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
... 34 frames truncated
"
请求
此错误是因为用于验证 jvm 中的 TLS 连接的 trustore 不信任用于 keycloak 服务器的证书。因此,将代码转换为令牌的请求永远不会完成。
您需要在 jvm trustore 中添加 CA 证书
当您处于 kubernetes 环境中时,更简单的方法可能是使用 keycloak 适配器 (https://www.keycloak.org/docs/latest/securing_apps/index.html#_java_adapter_config) 提供的功能:
- Trustore:使用特定的 TruStore 连接到 KeyCloak
- 禁用信任管理器:禁用证书验证(仅用于测试)